minder-cli 0.2.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.
- minder/__init__.py +12 -0
- minder/api/routers/prompts.py +177 -0
- minder/application/__init__.py +1 -0
- minder/application/admin/__init__.py +11 -0
- minder/application/admin/dto.py +453 -0
- minder/application/admin/jobs.py +327 -0
- minder/application/admin/use_cases.py +1895 -0
- minder/auth/__init__.py +12 -0
- minder/auth/context.py +26 -0
- minder/auth/middleware.py +70 -0
- minder/auth/principal.py +59 -0
- minder/auth/rate_limiter.py +89 -0
- minder/auth/rbac.py +60 -0
- minder/auth/service.py +541 -0
- minder/bootstrap/__init__.py +9 -0
- minder/bootstrap/providers.py +109 -0
- minder/bootstrap/transport.py +807 -0
- minder/cache/__init__.py +10 -0
- minder/cache/providers.py +140 -0
- minder/chunking/__init__.py +4 -0
- minder/chunking/code_splitter.py +184 -0
- minder/chunking/splitter.py +136 -0
- minder/cli.py +1542 -0
- minder/config.py +179 -0
- minder/continuity.py +363 -0
- minder/dev.py +160 -0
- minder/embedding/__init__.py +9 -0
- minder/embedding/base.py +7 -0
- minder/embedding/local.py +65 -0
- minder/embedding/openai.py +7 -0
- minder/graph/__init__.py +11 -0
- minder/graph/edges.py +13 -0
- minder/graph/executor.py +127 -0
- minder/graph/graph.py +263 -0
- minder/graph/nodes/__init__.py +27 -0
- minder/graph/nodes/evaluator.py +21 -0
- minder/graph/nodes/guard.py +64 -0
- minder/graph/nodes/llm.py +59 -0
- minder/graph/nodes/planning.py +30 -0
- minder/graph/nodes/reasoning.py +87 -0
- minder/graph/nodes/reranker.py +141 -0
- minder/graph/nodes/retriever.py +86 -0
- minder/graph/nodes/verification.py +230 -0
- minder/graph/nodes/workflow_planner.py +250 -0
- minder/graph/runtime.py +15 -0
- minder/graph/state.py +26 -0
- minder/llm/__init__.py +5 -0
- minder/llm/base.py +14 -0
- minder/llm/local.py +381 -0
- minder/llm/openai.py +89 -0
- minder/models/__init__.py +109 -0
- minder/models/base.py +10 -0
- minder/models/client.py +137 -0
- minder/models/document.py +34 -0
- minder/models/error.py +32 -0
- minder/models/graph.py +114 -0
- minder/models/history.py +32 -0
- minder/models/job.py +62 -0
- minder/models/prompt.py +41 -0
- minder/models/repository.py +62 -0
- minder/models/rule.py +68 -0
- minder/models/session.py +51 -0
- minder/models/skill.py +52 -0
- minder/models/user.py +41 -0
- minder/models/workflow.py +35 -0
- minder/observability/__init__.py +57 -0
- minder/observability/audit.py +243 -0
- minder/observability/logging.py +253 -0
- minder/observability/metrics.py +448 -0
- minder/observability/tracing.py +215 -0
- minder/presentation/__init__.py +1 -0
- minder/presentation/http/__init__.py +1 -0
- minder/presentation/http/admin/__init__.py +3 -0
- minder/presentation/http/admin/api.py +1309 -0
- minder/presentation/http/admin/context.py +94 -0
- minder/presentation/http/admin/dashboard.py +111 -0
- minder/presentation/http/admin/jobs.py +208 -0
- minder/presentation/http/admin/memories.py +185 -0
- minder/presentation/http/admin/prompts.py +219 -0
- minder/presentation/http/admin/routes.py +127 -0
- minder/presentation/http/admin/runtime.py +650 -0
- minder/presentation/http/admin/search.py +368 -0
- minder/presentation/http/admin/skills.py +230 -0
- minder/prompts/__init__.py +646 -0
- minder/prompts/formatter.py +142 -0
- minder/resources/__init__.py +318 -0
- minder/retrieval/__init__.py +5 -0
- minder/retrieval/hybrid.py +178 -0
- minder/retrieval/mmr.py +116 -0
- minder/retrieval/multi_hop.py +115 -0
- minder/runtime.py +15 -0
- minder/server.py +145 -0
- minder/store/__init__.py +64 -0
- minder/store/document.py +115 -0
- minder/store/error.py +82 -0
- minder/store/feedback.py +114 -0
- minder/store/graph.py +588 -0
- minder/store/history.py +57 -0
- minder/store/interfaces.py +512 -0
- minder/store/milvus/__init__.py +11 -0
- minder/store/milvus/client.py +26 -0
- minder/store/milvus/collections.py +15 -0
- minder/store/milvus/vector_store.py +232 -0
- minder/store/mongodb/__init__.py +11 -0
- minder/store/mongodb/client.py +49 -0
- minder/store/mongodb/indexes.py +90 -0
- minder/store/mongodb/operational_store.py +993 -0
- minder/store/relational.py +1087 -0
- minder/store/repo_state.py +58 -0
- minder/store/rule.py +93 -0
- minder/store/vector.py +79 -0
- minder/tools/__init__.py +47 -0
- minder/tools/auth.py +94 -0
- minder/tools/graph.py +839 -0
- minder/tools/ingest.py +353 -0
- minder/tools/memory.py +381 -0
- minder/tools/query.py +307 -0
- minder/tools/registry.py +269 -0
- minder/tools/repo_scanner.py +1266 -0
- minder/tools/search.py +15 -0
- minder/tools/session.py +316 -0
- minder/tools/skills.py +899 -0
- minder/tools/workflow.py +215 -0
- minder/transport/__init__.py +4 -0
- minder/transport/base.py +286 -0
- minder/transport/sse.py +252 -0
- minder/transport/stdio.py +29 -0
- minder_cli-0.2.0.dist-info/METADATA +318 -0
- minder_cli-0.2.0.dist-info/RECORD +132 -0
- minder_cli-0.2.0.dist-info/WHEEL +4 -0
- minder_cli-0.2.0.dist-info/entry_points.txt +2 -0
- minder_cli-0.2.0.dist-info/licenses/LICENSE +201 -0
minder/store/history.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from sqlalchemy import select
|
|
7
|
+
|
|
8
|
+
from minder.models.history import History
|
|
9
|
+
from minder.models.session import Session
|
|
10
|
+
from minder.store.relational import RelationalStore
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HistoryStore:
|
|
14
|
+
def __init__(self, store: RelationalStore) -> None:
|
|
15
|
+
self._store = store
|
|
16
|
+
|
|
17
|
+
async def create_history(
|
|
18
|
+
self,
|
|
19
|
+
session_id: uuid.UUID,
|
|
20
|
+
role: str,
|
|
21
|
+
content: str,
|
|
22
|
+
reasoning_trace: str | None = None,
|
|
23
|
+
tool_calls: dict[str, Any] | None = None,
|
|
24
|
+
tokens_used: int = 0,
|
|
25
|
+
latency_ms: int = 0,
|
|
26
|
+
) -> History:
|
|
27
|
+
async with self._store._session() as sess:
|
|
28
|
+
history = History(
|
|
29
|
+
id=uuid.uuid4(),
|
|
30
|
+
session_id=session_id,
|
|
31
|
+
role=role,
|
|
32
|
+
content=content,
|
|
33
|
+
reasoning_trace=reasoning_trace,
|
|
34
|
+
tool_calls=tool_calls or {},
|
|
35
|
+
tokens_used=tokens_used,
|
|
36
|
+
latency_ms=latency_ms,
|
|
37
|
+
)
|
|
38
|
+
sess.add(history)
|
|
39
|
+
await sess.flush()
|
|
40
|
+
await sess.refresh(history)
|
|
41
|
+
return history
|
|
42
|
+
|
|
43
|
+
async def list_history_for_session(self, session_id: uuid.UUID) -> list[History]:
|
|
44
|
+
async with self._store._session() as sess:
|
|
45
|
+
result = await sess.execute(
|
|
46
|
+
select(History).where(History.session_id == session_id)
|
|
47
|
+
)
|
|
48
|
+
return list(result.scalars().all())
|
|
49
|
+
|
|
50
|
+
async def list_history_for_user(self, user_id: uuid.UUID) -> list[History]:
|
|
51
|
+
async with self._store._session() as sess:
|
|
52
|
+
result = await sess.execute(
|
|
53
|
+
select(History)
|
|
54
|
+
.join(Session, Session.id == History.session_id)
|
|
55
|
+
.where(Session.user_id == user_id)
|
|
56
|
+
)
|
|
57
|
+
return list(result.scalars().all())
|
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Domain Repository Interfaces — Clean Architecture boundary.
|
|
3
|
+
|
|
4
|
+
These Protocol classes define the contracts that all store adapters
|
|
5
|
+
(SQLite, MongoDB, etc.) must satisfy. The application layer depends
|
|
6
|
+
only on these interfaces, never on concrete implementations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
import uuid
|
|
13
|
+
from typing import Any, Protocol, runtime_checkable
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# User Repository
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@runtime_checkable
|
|
22
|
+
class IUserRepository(Protocol):
|
|
23
|
+
async def create_user(self, **kwargs: Any) -> Any: ...
|
|
24
|
+
async def get_user_by_id(self, user_id: uuid.UUID) -> Any | None: ...
|
|
25
|
+
async def get_user_by_email(self, email: str) -> Any | None: ...
|
|
26
|
+
async def get_user_by_username(self, username: str) -> Any | None: ...
|
|
27
|
+
async def list_users(self, active_only: bool = True) -> list[Any]: ...
|
|
28
|
+
async def update_user(self, user_id: uuid.UUID, **kwargs: Any) -> Any | None: ...
|
|
29
|
+
async def delete_user(self, user_id: uuid.UUID) -> None: ...
|
|
30
|
+
async def has_admin_users(self) -> bool: ...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Skill Repository
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@runtime_checkable
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# Prompt Repository
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@runtime_checkable
|
|
46
|
+
class IPromptRepository(Protocol):
|
|
47
|
+
async def create_prompt(self, **kwargs: Any) -> Any: ...
|
|
48
|
+
async def get_prompt_by_id(self, prompt_id: uuid.UUID) -> Any | None: ...
|
|
49
|
+
async def get_prompt_by_name(self, name: str) -> Any | None: ...
|
|
50
|
+
async def list_prompts(self) -> list[Any]: ...
|
|
51
|
+
async def update_prompt(
|
|
52
|
+
self, prompt_id: uuid.UUID, **kwargs: Any
|
|
53
|
+
) -> Any | None: ...
|
|
54
|
+
async def delete_prompt(self, prompt_id: uuid.UUID) -> None: ...
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@runtime_checkable
|
|
58
|
+
class ISkillRepository(Protocol):
|
|
59
|
+
async def create_skill(self, **kwargs: Any) -> Any: ...
|
|
60
|
+
async def get_skill_by_id(self, skill_id: uuid.UUID) -> Any | None: ...
|
|
61
|
+
async def list_skills(self) -> list[Any]: ...
|
|
62
|
+
async def update_skill(self, skill_id: uuid.UUID, **kwargs: Any) -> Any | None: ...
|
|
63
|
+
async def delete_skill(self, skill_id: uuid.UUID) -> None: ...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
# Session Repository
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@runtime_checkable
|
|
72
|
+
class ISessionRepository(Protocol):
|
|
73
|
+
async def create_session(self, **kwargs: Any) -> Any: ...
|
|
74
|
+
async def get_session_by_id(self, session_id: uuid.UUID) -> Any | None: ...
|
|
75
|
+
async def get_sessions_by_user(self, user_id: uuid.UUID) -> list[Any]: ...
|
|
76
|
+
async def get_sessions_by_client(self, client_id: uuid.UUID) -> list[Any]: ...
|
|
77
|
+
async def find_session_by_name(
|
|
78
|
+
self,
|
|
79
|
+
name: str,
|
|
80
|
+
*,
|
|
81
|
+
user_id: uuid.UUID | None = None,
|
|
82
|
+
client_id: uuid.UUID | None = None,
|
|
83
|
+
) -> Any | None: ...
|
|
84
|
+
async def update_session(
|
|
85
|
+
self, session_id: uuid.UUID, **kwargs: Any
|
|
86
|
+
) -> Any | None: ...
|
|
87
|
+
async def delete_session(self, session_id: uuid.UUID) -> None: ...
|
|
88
|
+
async def cleanup_expired_sessions(
|
|
89
|
+
self,
|
|
90
|
+
*,
|
|
91
|
+
now: datetime | None = None,
|
|
92
|
+
user_id: uuid.UUID | None = None,
|
|
93
|
+
client_id: uuid.UUID | None = None,
|
|
94
|
+
) -> dict[str, int]: ...
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# Workflow Repository
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@runtime_checkable
|
|
103
|
+
class IWorkflowRepository(Protocol):
|
|
104
|
+
async def create_workflow(self, **kwargs: Any) -> Any: ...
|
|
105
|
+
async def get_workflow_by_id(self, workflow_id: uuid.UUID) -> Any | None: ...
|
|
106
|
+
async def get_workflow_by_name(self, name: str) -> Any | None: ...
|
|
107
|
+
async def list_workflows(self) -> list[Any]: ...
|
|
108
|
+
async def update_workflow(
|
|
109
|
+
self, workflow_id: uuid.UUID, **kwargs: Any
|
|
110
|
+
) -> Any | None: ...
|
|
111
|
+
async def delete_workflow(self, workflow_id: uuid.UUID) -> None: ...
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
# Repository (code repository) Repository
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@runtime_checkable
|
|
120
|
+
class IRepositoryRepo(Protocol):
|
|
121
|
+
async def create_repository(self, **kwargs: Any) -> Any: ...
|
|
122
|
+
async def get_repository_by_id(self, repo_id: uuid.UUID) -> Any | None: ...
|
|
123
|
+
async def get_repository_by_name(self, repo_name: str) -> Any | None: ...
|
|
124
|
+
async def list_repositories(self) -> list[Any]: ...
|
|
125
|
+
async def update_repository(
|
|
126
|
+
self, repo_id: uuid.UUID, **kwargs: Any
|
|
127
|
+
) -> Any | None: ...
|
|
128
|
+
async def delete_repository(self, repo_id: uuid.UUID) -> None: ...
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# ---------------------------------------------------------------------------
|
|
132
|
+
# Workflow State Repository
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@runtime_checkable
|
|
137
|
+
class IWorkflowStateRepository(Protocol):
|
|
138
|
+
async def create_workflow_state(self, **kwargs: Any) -> Any: ...
|
|
139
|
+
async def get_workflow_state_by_id(self, state_id: uuid.UUID) -> Any | None: ...
|
|
140
|
+
async def get_workflow_state_by_repo(self, repo_id: uuid.UUID) -> Any | None: ...
|
|
141
|
+
async def update_workflow_state(
|
|
142
|
+
self, state_id: uuid.UUID, **kwargs: Any
|
|
143
|
+
) -> Any | None: ...
|
|
144
|
+
async def delete_workflow_state(self, state_id: uuid.UUID) -> None: ...
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
# Document Repository
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@runtime_checkable
|
|
153
|
+
class IDocumentRepository(Protocol):
|
|
154
|
+
async def create_document(
|
|
155
|
+
self,
|
|
156
|
+
title: str,
|
|
157
|
+
content: str,
|
|
158
|
+
doc_type: str,
|
|
159
|
+
source_path: str,
|
|
160
|
+
project: str,
|
|
161
|
+
*,
|
|
162
|
+
chunks: dict[str, Any] | None = None,
|
|
163
|
+
embedding: list[float] | None = None,
|
|
164
|
+
) -> Any: ...
|
|
165
|
+
|
|
166
|
+
async def get_document_by_path(
|
|
167
|
+
self, source_path: str, *, project: str | None = None
|
|
168
|
+
) -> Any | None: ...
|
|
169
|
+
|
|
170
|
+
async def get_documents_by_ids(self, doc_ids: list[uuid.UUID]) -> list[Any]: ...
|
|
171
|
+
|
|
172
|
+
async def list_documents(self, project: str | None = None) -> list[Any]: ...
|
|
173
|
+
|
|
174
|
+
async def upsert_document(
|
|
175
|
+
self,
|
|
176
|
+
*,
|
|
177
|
+
title: str,
|
|
178
|
+
content: str,
|
|
179
|
+
doc_type: str,
|
|
180
|
+
source_path: str,
|
|
181
|
+
project: str,
|
|
182
|
+
chunks: dict[str, Any] | None = None,
|
|
183
|
+
embedding: list[float] | None = None,
|
|
184
|
+
) -> Any: ...
|
|
185
|
+
|
|
186
|
+
async def delete_documents_not_in_paths(
|
|
187
|
+
self, *, project: str, keep_paths: set[str]
|
|
188
|
+
) -> None: ...
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# ---------------------------------------------------------------------------
|
|
192
|
+
# History Repository
|
|
193
|
+
# ---------------------------------------------------------------------------
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@runtime_checkable
|
|
197
|
+
class IHistoryRepository(Protocol):
|
|
198
|
+
async def create_history(
|
|
199
|
+
self,
|
|
200
|
+
session_id: uuid.UUID,
|
|
201
|
+
role: str,
|
|
202
|
+
content: str,
|
|
203
|
+
reasoning_trace: str | None = None,
|
|
204
|
+
tool_calls: dict[str, Any] | None = None,
|
|
205
|
+
tokens_used: int = 0,
|
|
206
|
+
latency_ms: int = 0,
|
|
207
|
+
) -> Any: ...
|
|
208
|
+
|
|
209
|
+
async def list_history_for_session(self, session_id: uuid.UUID) -> list[Any]: ...
|
|
210
|
+
async def list_history_for_user(self, user_id: uuid.UUID) -> list[Any]: ...
|
|
211
|
+
async def delete_history_for_session(self, session_id: uuid.UUID) -> int: ...
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# ---------------------------------------------------------------------------
|
|
215
|
+
# Error Repository
|
|
216
|
+
# ---------------------------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@runtime_checkable
|
|
220
|
+
class IErrorRepository(Protocol):
|
|
221
|
+
async def create_error(
|
|
222
|
+
self,
|
|
223
|
+
error_code: str,
|
|
224
|
+
error_message: str,
|
|
225
|
+
stack_trace: str | None = None,
|
|
226
|
+
context: dict[str, Any] | None = None,
|
|
227
|
+
resolution: str | None = None,
|
|
228
|
+
embedding: list[float] | None = None,
|
|
229
|
+
resolved: bool = False,
|
|
230
|
+
) -> Any: ...
|
|
231
|
+
|
|
232
|
+
async def list_errors(self) -> list[Any]: ...
|
|
233
|
+
async def search_errors(
|
|
234
|
+
self, query: str, limit: int = 5
|
|
235
|
+
) -> list[dict[str, Any]]: ...
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
# Rule Repository
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@runtime_checkable
|
|
244
|
+
class IRuleRepository(Protocol):
|
|
245
|
+
async def create_rule(self, **kwargs: Any) -> Any: ...
|
|
246
|
+
async def get_rule_by_id(self, rule_id: uuid.UUID) -> Any | None: ...
|
|
247
|
+
async def list_rules(self) -> list[Any]: ...
|
|
248
|
+
async def list_by_scope(self, scope: str) -> list[Any]: ...
|
|
249
|
+
async def list_active(self) -> list[Any]: ...
|
|
250
|
+
async def update_rule(self, rule_id: uuid.UUID, **kwargs: Any) -> Any | None: ...
|
|
251
|
+
async def delete_rule(self, rule_id: uuid.UUID) -> None: ...
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
# ---------------------------------------------------------------------------
|
|
255
|
+
# Feedback Repository
|
|
256
|
+
# ---------------------------------------------------------------------------
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@runtime_checkable
|
|
260
|
+
class IFeedbackRepository(Protocol):
|
|
261
|
+
async def create_feedback(self, **kwargs: Any) -> Any: ...
|
|
262
|
+
async def get_feedback_by_id(self, feedback_id: uuid.UUID) -> Any | None: ...
|
|
263
|
+
async def list_feedback(self) -> list[Any]: ...
|
|
264
|
+
async def list_by_entity(
|
|
265
|
+
self, entity_type: str, entity_id: uuid.UUID
|
|
266
|
+
) -> list[Any]: ...
|
|
267
|
+
async def average_rating(self, entity_id: uuid.UUID) -> float | None: ...
|
|
268
|
+
async def update_feedback(
|
|
269
|
+
self, feedback_id: uuid.UUID, **kwargs: Any
|
|
270
|
+
) -> Any | None: ...
|
|
271
|
+
async def delete_feedback(self, feedback_id: uuid.UUID) -> None: ...
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# ---------------------------------------------------------------------------
|
|
275
|
+
# Knowledge Graph Repository
|
|
276
|
+
# ---------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@runtime_checkable
|
|
280
|
+
class IGraphRepository(Protocol):
|
|
281
|
+
async def add_node(
|
|
282
|
+
self,
|
|
283
|
+
node_type: str,
|
|
284
|
+
name: str,
|
|
285
|
+
metadata: dict[str, Any] | None = None,
|
|
286
|
+
node_id: uuid.UUID | None = None,
|
|
287
|
+
*,
|
|
288
|
+
repo_id: str = "",
|
|
289
|
+
branch: str = "",
|
|
290
|
+
) -> Any: ...
|
|
291
|
+
async def upsert_node(
|
|
292
|
+
self,
|
|
293
|
+
node_type: str,
|
|
294
|
+
name: str,
|
|
295
|
+
metadata: dict[str, Any] | None = None,
|
|
296
|
+
*,
|
|
297
|
+
repo_id: str = "",
|
|
298
|
+
branch: str = "",
|
|
299
|
+
) -> Any: ...
|
|
300
|
+
async def get_node(self, node_id: uuid.UUID) -> Any | None: ...
|
|
301
|
+
async def get_node_by_name(
|
|
302
|
+
self,
|
|
303
|
+
node_type: str,
|
|
304
|
+
name: str,
|
|
305
|
+
*,
|
|
306
|
+
repo_id: str = "",
|
|
307
|
+
branch: str = "",
|
|
308
|
+
) -> Any | None: ...
|
|
309
|
+
async def list_nodes(self) -> list[Any]: ...
|
|
310
|
+
async def list_nodes_by_scope(
|
|
311
|
+
self, *, repo_id: str, branch: str | None = None
|
|
312
|
+
) -> list[Any]: ...
|
|
313
|
+
async def list_edges(self) -> list[Any]: ...
|
|
314
|
+
async def list_edges_by_scope(self, *, repo_id: str) -> list[Any]: ...
|
|
315
|
+
async def query_by_type(
|
|
316
|
+
self, node_type: str, *, repo_id: str = ""
|
|
317
|
+
) -> list[Any]: ...
|
|
318
|
+
async def delete_node(self, node_id: uuid.UUID) -> None: ...
|
|
319
|
+
async def delete_nodes_by_scope(
|
|
320
|
+
self,
|
|
321
|
+
*,
|
|
322
|
+
repo_id: str,
|
|
323
|
+
branch: str | None = None,
|
|
324
|
+
paths: set[str] | None = None,
|
|
325
|
+
) -> int: ...
|
|
326
|
+
async def add_edge(
|
|
327
|
+
self,
|
|
328
|
+
source_id: uuid.UUID,
|
|
329
|
+
target_id: uuid.UUID,
|
|
330
|
+
relation: str,
|
|
331
|
+
weight: float = 1.0,
|
|
332
|
+
edge_id: uuid.UUID | None = None,
|
|
333
|
+
*,
|
|
334
|
+
repo_id: str = "",
|
|
335
|
+
) -> Any: ...
|
|
336
|
+
async def upsert_edge(
|
|
337
|
+
self,
|
|
338
|
+
source_id: uuid.UUID,
|
|
339
|
+
target_id: uuid.UUID,
|
|
340
|
+
relation: str,
|
|
341
|
+
weight: float = 1.0,
|
|
342
|
+
*,
|
|
343
|
+
repo_id: str = "",
|
|
344
|
+
) -> Any: ...
|
|
345
|
+
async def delete_edge(self, edge_id: uuid.UUID) -> None: ...
|
|
346
|
+
async def get_neighbors(
|
|
347
|
+
self,
|
|
348
|
+
node_id: uuid.UUID,
|
|
349
|
+
*,
|
|
350
|
+
direction: str = "out",
|
|
351
|
+
relation: str | None = None,
|
|
352
|
+
) -> list[Any]: ...
|
|
353
|
+
async def get_path(
|
|
354
|
+
self,
|
|
355
|
+
source_id: uuid.UUID,
|
|
356
|
+
target_id: uuid.UUID,
|
|
357
|
+
*,
|
|
358
|
+
max_depth: int = 6,
|
|
359
|
+
) -> list[Any]: ...
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
# ---------------------------------------------------------------------------
|
|
363
|
+
# Client Gateway Repository
|
|
364
|
+
# ---------------------------------------------------------------------------
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@runtime_checkable
|
|
368
|
+
class IClientRepository(Protocol):
|
|
369
|
+
async def create_client(self, **kwargs: Any) -> Any: ...
|
|
370
|
+
async def get_client_by_id(self, client_id: uuid.UUID) -> Any | None: ...
|
|
371
|
+
async def get_client_by_slug(self, slug: str) -> Any | None: ...
|
|
372
|
+
async def list_clients(self) -> list[Any]: ...
|
|
373
|
+
async def update_client(
|
|
374
|
+
self, client_id: uuid.UUID, **kwargs: Any
|
|
375
|
+
) -> Any | None: ...
|
|
376
|
+
async def create_client_api_key(self, **kwargs: Any) -> Any: ...
|
|
377
|
+
async def list_client_api_keys(self, client_id: uuid.UUID) -> list[Any]: ...
|
|
378
|
+
async def update_client_api_key(
|
|
379
|
+
self, key_id: uuid.UUID, **kwargs: Any
|
|
380
|
+
) -> Any | None: ...
|
|
381
|
+
async def create_client_session(self, **kwargs: Any) -> Any: ...
|
|
382
|
+
async def count_active_client_sessions(self) -> int: ...
|
|
383
|
+
async def get_client_session_by_token_id(self, token_id: str) -> Any | None: ...
|
|
384
|
+
async def update_client_session(
|
|
385
|
+
self, session_id: uuid.UUID, **kwargs: Any
|
|
386
|
+
) -> Any | None: ...
|
|
387
|
+
async def create_audit_log(self, **kwargs: Any) -> Any: ...
|
|
388
|
+
async def list_audit_logs(
|
|
389
|
+
self,
|
|
390
|
+
*,
|
|
391
|
+
actor_id: str | None = None,
|
|
392
|
+
event_type: str | None = None,
|
|
393
|
+
outcome: str | None = None,
|
|
394
|
+
limit: int | None = None,
|
|
395
|
+
offset: int = 0,
|
|
396
|
+
) -> list[Any]: ...
|
|
397
|
+
async def count_audit_logs(
|
|
398
|
+
self,
|
|
399
|
+
*,
|
|
400
|
+
actor_id: str | None = None,
|
|
401
|
+
event_type: str | None = None,
|
|
402
|
+
outcome: str | None = None,
|
|
403
|
+
) -> int: ...
|
|
404
|
+
async def get_audit_summary(
|
|
405
|
+
self,
|
|
406
|
+
*,
|
|
407
|
+
actor_id: str | None = None,
|
|
408
|
+
event_type: str | None = None,
|
|
409
|
+
outcome: str | None = None,
|
|
410
|
+
group_by: str = "event_type",
|
|
411
|
+
) -> dict[str, int]: ...
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
@runtime_checkable
|
|
415
|
+
class IAdminJobRepository(Protocol):
|
|
416
|
+
async def create_admin_job(self, **kwargs: Any) -> Any: ...
|
|
417
|
+
async def get_admin_job_by_id(self, job_id: uuid.UUID) -> Any | None: ...
|
|
418
|
+
async def list_admin_jobs(
|
|
419
|
+
self,
|
|
420
|
+
*,
|
|
421
|
+
job_type: str | None = None,
|
|
422
|
+
status: str | None = None,
|
|
423
|
+
requested_by_user_id: uuid.UUID | None = None,
|
|
424
|
+
limit: int | None = None,
|
|
425
|
+
offset: int = 0,
|
|
426
|
+
) -> list[Any]: ...
|
|
427
|
+
async def update_admin_job(
|
|
428
|
+
self, job_id: uuid.UUID, **kwargs: Any
|
|
429
|
+
) -> Any | None: ...
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
# ---------------------------------------------------------------------------
|
|
433
|
+
# Cache Provider (for Redis)
|
|
434
|
+
# ---------------------------------------------------------------------------
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@runtime_checkable
|
|
438
|
+
class ICacheProvider(Protocol):
|
|
439
|
+
async def get(self, key: str) -> str | None: ...
|
|
440
|
+
async def set(self, key: str, value: str, *, ttl: int | None = None) -> None: ...
|
|
441
|
+
async def delete(self, key: str) -> None: ...
|
|
442
|
+
async def exists(self, key: str) -> bool: ...
|
|
443
|
+
async def expire(self, key: str, ttl: int) -> None: ...
|
|
444
|
+
async def incr(self, key: str) -> int: ...
|
|
445
|
+
async def keys(self, pattern: str) -> list[str]: ...
|
|
446
|
+
async def flush_namespace(self, namespace: str) -> None: ...
|
|
447
|
+
async def health_check(self) -> bool: ...
|
|
448
|
+
async def close(self) -> None: ...
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
# ---------------------------------------------------------------------------
|
|
452
|
+
# Vector Store
|
|
453
|
+
# ---------------------------------------------------------------------------
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@runtime_checkable
|
|
457
|
+
class IVectorStore(Protocol):
|
|
458
|
+
async def upsert_document(
|
|
459
|
+
self,
|
|
460
|
+
doc_id: uuid.UUID,
|
|
461
|
+
embedding: list[float],
|
|
462
|
+
payload: dict[str, Any],
|
|
463
|
+
) -> None: ...
|
|
464
|
+
|
|
465
|
+
async def delete_documents(self, doc_ids: list[uuid.UUID]) -> None: ...
|
|
466
|
+
|
|
467
|
+
async def search_documents(
|
|
468
|
+
self,
|
|
469
|
+
query_embedding: list[float],
|
|
470
|
+
*,
|
|
471
|
+
project: str | None = None,
|
|
472
|
+
doc_types: set[str] | None = None,
|
|
473
|
+
limit: int = 5,
|
|
474
|
+
score_threshold: float = 0.0,
|
|
475
|
+
) -> list[dict[str, Any]]: ...
|
|
476
|
+
|
|
477
|
+
async def setup(self) -> None: ...
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
# ---------------------------------------------------------------------------
|
|
481
|
+
# Operational Store — composite interface for backwards compatibility
|
|
482
|
+
# ---------------------------------------------------------------------------
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@runtime_checkable
|
|
486
|
+
class IOperationalStore(
|
|
487
|
+
IUserRepository,
|
|
488
|
+
ISkillRepository,
|
|
489
|
+
IPromptRepository,
|
|
490
|
+
ISessionRepository,
|
|
491
|
+
IWorkflowRepository,
|
|
492
|
+
IRepositoryRepo,
|
|
493
|
+
IWorkflowStateRepository,
|
|
494
|
+
IDocumentRepository,
|
|
495
|
+
IHistoryRepository,
|
|
496
|
+
IErrorRepository,
|
|
497
|
+
IRuleRepository,
|
|
498
|
+
IFeedbackRepository,
|
|
499
|
+
IClientRepository,
|
|
500
|
+
IAdminJobRepository,
|
|
501
|
+
Protocol,
|
|
502
|
+
):
|
|
503
|
+
"""
|
|
504
|
+
Composite interface matching the current RelationalStore surface.
|
|
505
|
+
|
|
506
|
+
This allows existing code that depends on a single store object
|
|
507
|
+
(e.g., server.py, tools) to continue working while we migrate
|
|
508
|
+
individual repositories to MongoDB behind the scenes.
|
|
509
|
+
"""
|
|
510
|
+
|
|
511
|
+
async def init_db(self) -> None: ...
|
|
512
|
+
async def dispose(self) -> None: ...
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Milvus Client — connection wrapper.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
from pymilvus import MilvusClient as PyMilvusClient # type: ignore[import-untyped]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MilvusClient:
|
|
12
|
+
"""Wrapper around PyMilvus client (which is blocking, so we run it in executor if needed)."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, uri: str = "http://localhost:19530") -> None:
|
|
15
|
+
self.uri = uri
|
|
16
|
+
self.client = PyMilvusClient(uri=uri)
|
|
17
|
+
|
|
18
|
+
async def health_check(self) -> bool:
|
|
19
|
+
"""Pings the Milvus server asynchronously."""
|
|
20
|
+
loop = asyncio.get_running_loop()
|
|
21
|
+
try:
|
|
22
|
+
# We list collections as a proxy for health check
|
|
23
|
+
await loop.run_in_executor(None, self.client.list_collections)
|
|
24
|
+
return True
|
|
25
|
+
except Exception:
|
|
26
|
+
return False
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Milvus Collections — schema definitions.
|
|
3
|
+
"""
|
|
4
|
+
from pymilvus import CollectionSchema, DataType, FieldSchema # type: ignore[import-untyped]
|
|
5
|
+
|
|
6
|
+
def get_document_schema(dimensions: int = 768) -> CollectionSchema:
|
|
7
|
+
fields = [
|
|
8
|
+
FieldSchema(name="id", dtype=DataType.VARCHAR, max_length=64, is_primary=True),
|
|
9
|
+
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=dimensions),
|
|
10
|
+
FieldSchema(name="project", dtype=DataType.VARCHAR, max_length=256),
|
|
11
|
+
FieldSchema(name="doc_type", dtype=DataType.VARCHAR, max_length=64),
|
|
12
|
+
# Payload stored as JSON string because Milvus JSON handles unstructured data
|
|
13
|
+
FieldSchema(name="payload", dtype=DataType.JSON),
|
|
14
|
+
]
|
|
15
|
+
return CollectionSchema(fields, description="Document chunks for RAG")
|