kodit 0.4.3__py3-none-any.whl → 0.5.1__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.

Potentially problematic release.


This version of kodit might be problematic. Click here for more details.

Files changed (135) hide show
  1. kodit/_version.py +2 -2
  2. kodit/app.py +51 -23
  3. kodit/application/factories/reporting_factory.py +6 -2
  4. kodit/application/factories/server_factory.py +353 -0
  5. kodit/application/services/code_search_application_service.py +144 -0
  6. kodit/application/services/commit_indexing_application_service.py +700 -0
  7. kodit/application/services/indexing_worker_service.py +13 -44
  8. kodit/application/services/queue_service.py +24 -3
  9. kodit/application/services/reporting.py +0 -2
  10. kodit/application/services/sync_scheduler.py +15 -31
  11. kodit/cli.py +2 -753
  12. kodit/cli_utils.py +2 -9
  13. kodit/config.py +4 -97
  14. kodit/database.py +38 -1
  15. kodit/domain/enrichments/__init__.py +1 -0
  16. kodit/domain/enrichments/architecture/__init__.py +1 -0
  17. kodit/domain/enrichments/architecture/architecture.py +20 -0
  18. kodit/domain/enrichments/architecture/physical/__init__.py +1 -0
  19. kodit/domain/enrichments/architecture/physical/discovery_notes.py +14 -0
  20. kodit/domain/enrichments/architecture/physical/formatter.py +11 -0
  21. kodit/domain/enrichments/architecture/physical/physical.py +17 -0
  22. kodit/domain/enrichments/development/__init__.py +1 -0
  23. kodit/domain/enrichments/development/development.py +18 -0
  24. kodit/domain/enrichments/development/snippet/__init__.py +1 -0
  25. kodit/domain/enrichments/development/snippet/snippet.py +21 -0
  26. kodit/domain/enrichments/enricher.py +17 -0
  27. kodit/domain/enrichments/enrichment.py +39 -0
  28. kodit/domain/enrichments/request.py +12 -0
  29. kodit/domain/enrichments/response.py +11 -0
  30. kodit/domain/enrichments/usage/__init__.py +1 -0
  31. kodit/domain/enrichments/usage/api_docs.py +19 -0
  32. kodit/domain/enrichments/usage/usage.py +18 -0
  33. kodit/domain/{entities.py → entities/__init__.py} +50 -195
  34. kodit/domain/entities/git.py +190 -0
  35. kodit/domain/factories/__init__.py +1 -0
  36. kodit/domain/factories/git_repo_factory.py +76 -0
  37. kodit/domain/protocols.py +264 -64
  38. kodit/domain/services/bm25_service.py +5 -1
  39. kodit/domain/services/embedding_service.py +3 -0
  40. kodit/domain/services/enrichment_service.py +9 -30
  41. kodit/domain/services/git_repository_service.py +429 -0
  42. kodit/domain/services/git_service.py +300 -0
  43. kodit/domain/services/physical_architecture_service.py +182 -0
  44. kodit/domain/services/task_status_query_service.py +2 -2
  45. kodit/domain/value_objects.py +87 -135
  46. kodit/infrastructure/api/client/__init__.py +0 -2
  47. kodit/infrastructure/api/v1/__init__.py +0 -4
  48. kodit/infrastructure/api/v1/dependencies.py +92 -46
  49. kodit/infrastructure/api/v1/routers/__init__.py +0 -6
  50. kodit/infrastructure/api/v1/routers/commits.py +352 -0
  51. kodit/infrastructure/api/v1/routers/queue.py +2 -2
  52. kodit/infrastructure/api/v1/routers/repositories.py +282 -0
  53. kodit/infrastructure/api/v1/routers/search.py +31 -14
  54. kodit/infrastructure/api/v1/schemas/__init__.py +0 -24
  55. kodit/infrastructure/api/v1/schemas/commit.py +96 -0
  56. kodit/infrastructure/api/v1/schemas/context.py +2 -0
  57. kodit/infrastructure/api/v1/schemas/enrichment.py +29 -0
  58. kodit/infrastructure/api/v1/schemas/repository.py +128 -0
  59. kodit/infrastructure/api/v1/schemas/search.py +12 -9
  60. kodit/infrastructure/api/v1/schemas/snippet.py +58 -0
  61. kodit/infrastructure/api/v1/schemas/tag.py +31 -0
  62. kodit/infrastructure/api/v1/schemas/task_status.py +2 -0
  63. kodit/infrastructure/bm25/local_bm25_repository.py +16 -4
  64. kodit/infrastructure/bm25/vectorchord_bm25_repository.py +68 -52
  65. kodit/infrastructure/cloning/git/git_python_adaptor.py +534 -0
  66. kodit/infrastructure/cloning/git/working_copy.py +1 -1
  67. kodit/infrastructure/embedding/embedding_factory.py +3 -2
  68. kodit/infrastructure/embedding/local_vector_search_repository.py +1 -1
  69. kodit/infrastructure/embedding/vectorchord_vector_search_repository.py +111 -84
  70. kodit/infrastructure/enricher/__init__.py +1 -0
  71. kodit/infrastructure/enricher/enricher_factory.py +53 -0
  72. kodit/infrastructure/{enrichment/litellm_enrichment_provider.py → enricher/litellm_enricher.py} +36 -56
  73. kodit/infrastructure/{enrichment/local_enrichment_provider.py → enricher/local_enricher.py} +19 -24
  74. kodit/infrastructure/enricher/null_enricher.py +36 -0
  75. kodit/infrastructure/indexing/fusion_service.py +1 -1
  76. kodit/infrastructure/mappers/enrichment_mapper.py +83 -0
  77. kodit/infrastructure/mappers/git_mapper.py +193 -0
  78. kodit/infrastructure/mappers/snippet_mapper.py +104 -0
  79. kodit/infrastructure/mappers/task_mapper.py +5 -44
  80. kodit/infrastructure/physical_architecture/__init__.py +1 -0
  81. kodit/infrastructure/physical_architecture/detectors/__init__.py +1 -0
  82. kodit/infrastructure/physical_architecture/detectors/docker_compose_detector.py +336 -0
  83. kodit/infrastructure/physical_architecture/formatters/__init__.py +1 -0
  84. kodit/infrastructure/physical_architecture/formatters/narrative_formatter.py +149 -0
  85. kodit/infrastructure/reporting/log_progress.py +8 -5
  86. kodit/infrastructure/reporting/telemetry_progress.py +21 -0
  87. kodit/infrastructure/slicing/api_doc_extractor.py +836 -0
  88. kodit/infrastructure/slicing/ast_analyzer.py +1128 -0
  89. kodit/infrastructure/slicing/slicer.py +87 -421
  90. kodit/infrastructure/sqlalchemy/embedding_repository.py +43 -23
  91. kodit/infrastructure/sqlalchemy/enrichment_v2_repository.py +118 -0
  92. kodit/infrastructure/sqlalchemy/entities.py +402 -158
  93. kodit/infrastructure/sqlalchemy/git_branch_repository.py +274 -0
  94. kodit/infrastructure/sqlalchemy/git_commit_repository.py +346 -0
  95. kodit/infrastructure/sqlalchemy/git_repository.py +262 -0
  96. kodit/infrastructure/sqlalchemy/git_tag_repository.py +268 -0
  97. kodit/infrastructure/sqlalchemy/snippet_v2_repository.py +479 -0
  98. kodit/infrastructure/sqlalchemy/task_repository.py +29 -23
  99. kodit/infrastructure/sqlalchemy/task_status_repository.py +24 -12
  100. kodit/infrastructure/sqlalchemy/unit_of_work.py +10 -14
  101. kodit/mcp.py +12 -30
  102. kodit/migrations/env.py +1 -0
  103. kodit/migrations/versions/04b80f802e0c_foreign_key_review.py +100 -0
  104. kodit/migrations/versions/19f8c7faf8b9_add_generic_enrichment_type.py +260 -0
  105. kodit/migrations/versions/7f15f878c3a1_add_new_git_entities.py +690 -0
  106. kodit/migrations/versions/f9e5ef5e688f_add_git_commits_number.py +43 -0
  107. kodit/py.typed +0 -0
  108. kodit/utils/dump_config.py +361 -0
  109. kodit/utils/dump_openapi.py +6 -4
  110. kodit/utils/path_utils.py +29 -0
  111. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/METADATA +3 -3
  112. kodit-0.5.1.dist-info/RECORD +168 -0
  113. kodit/application/factories/code_indexing_factory.py +0 -195
  114. kodit/application/services/auto_indexing_service.py +0 -99
  115. kodit/application/services/code_indexing_application_service.py +0 -410
  116. kodit/domain/services/index_query_service.py +0 -70
  117. kodit/domain/services/index_service.py +0 -269
  118. kodit/infrastructure/api/client/index_client.py +0 -57
  119. kodit/infrastructure/api/v1/routers/indexes.py +0 -164
  120. kodit/infrastructure/api/v1/schemas/index.py +0 -101
  121. kodit/infrastructure/bm25/bm25_factory.py +0 -28
  122. kodit/infrastructure/cloning/__init__.py +0 -1
  123. kodit/infrastructure/cloning/metadata.py +0 -98
  124. kodit/infrastructure/enrichment/__init__.py +0 -1
  125. kodit/infrastructure/enrichment/enrichment_factory.py +0 -52
  126. kodit/infrastructure/enrichment/null_enrichment_provider.py +0 -19
  127. kodit/infrastructure/mappers/index_mapper.py +0 -345
  128. kodit/infrastructure/reporting/tdqm_progress.py +0 -38
  129. kodit/infrastructure/slicing/language_detection_service.py +0 -18
  130. kodit/infrastructure/sqlalchemy/index_repository.py +0 -646
  131. kodit-0.4.3.dist-info/RECORD +0 -125
  132. /kodit/infrastructure/{enrichment → enricher}/utils.py +0 -0
  133. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/WHEEL +0 -0
  134. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/entry_points.txt +0 -0
  135. {kodit-0.4.3.dist-info → kodit-0.5.1.dist-info}/licenses/LICENSE +0 -0
kodit/domain/protocols.py CHANGED
@@ -1,19 +1,28 @@
1
1
  """Repository protocol interfaces for the domain layer."""
2
2
 
3
- from collections.abc import Sequence
4
- from typing import Protocol
3
+ from abc import ABC, abstractmethod
4
+ from pathlib import Path
5
+ from typing import Any, Protocol
5
6
 
6
7
  from pydantic import AnyUrl
7
8
 
8
9
  from kodit.domain.entities import (
9
- Index,
10
- Snippet,
11
- SnippetWithContext,
12
10
  Task,
13
11
  TaskStatus,
14
- WorkingCopy,
15
12
  )
16
- from kodit.domain.value_objects import MultiSearchRequest, TaskType
13
+ from kodit.domain.entities.git import (
14
+ GitBranch,
15
+ GitCommit,
16
+ GitRepo,
17
+ GitTag,
18
+ SnippetV2,
19
+ )
20
+ from kodit.domain.value_objects import (
21
+ FusionRequest,
22
+ FusionResult,
23
+ MultiSearchRequest,
24
+ TaskOperation,
25
+ )
17
26
 
18
27
 
19
28
  class TaskRepository(Protocol):
@@ -30,96 +39,287 @@ class TaskRepository(Protocol):
30
39
  """Get a task by ID."""
31
40
  ...
32
41
 
33
- async def take(self) -> Task | None:
42
+ async def next(self) -> Task | None:
34
43
  """Take a task for processing."""
35
44
  ...
36
45
 
46
+ async def remove(self, task: Task) -> None:
47
+ """Remove a task."""
48
+ ...
49
+
37
50
  async def update(self, task: Task) -> None:
38
51
  """Update a task."""
39
52
  ...
40
53
 
41
- async def list(self, task_type: TaskType | None = None) -> list[Task]:
54
+ async def list(self, task_operation: TaskOperation | None = None) -> list[Task]:
42
55
  """List tasks with optional status filter."""
43
56
  ...
44
57
 
45
58
 
46
- class IndexRepository(Protocol):
47
- """Repository interface for Index entities."""
59
+ class ReportingModule(Protocol):
60
+ """Reporting module."""
48
61
 
49
- async def create(self, uri: AnyUrl, working_copy: WorkingCopy) -> Index:
50
- """Create an index for a source."""
62
+ async def on_change(self, progress: TaskStatus) -> None:
63
+ """On step changed."""
51
64
  ...
52
65
 
53
- async def update(self, index: Index) -> None:
54
- """Update an index."""
55
- ...
56
66
 
57
- async def get(self, index_id: int) -> Index | None:
58
- """Get an index by ID."""
59
- ...
67
+ class TaskStatusRepository(Protocol):
68
+ """Repository interface for persisting progress state only."""
60
69
 
61
- async def delete(self, index: Index) -> None:
62
- """Delete an index."""
70
+ async def save(self, status: TaskStatus) -> None:
71
+ """Save a progress state."""
63
72
  ...
64
73
 
65
- async def all(self) -> list[Index]:
66
- """List all indexes."""
74
+ async def load_with_hierarchy(
75
+ self, trackable_type: str, trackable_id: int
76
+ ) -> list[TaskStatus]:
77
+ """Load progress states with IDs and parent IDs from database."""
67
78
  ...
68
79
 
69
- async def get_by_uri(self, uri: AnyUrl) -> Index | None:
70
- """Get an index by source URI."""
80
+ async def delete(self, status: TaskStatus) -> None:
81
+ """Delete a progress state."""
71
82
  ...
72
83
 
73
- async def update_index_timestamp(self, index_id: int) -> None:
74
- """Update the timestamp of an index."""
75
- ...
76
84
 
77
- async def add_snippets(self, index_id: int, snippets: list[Snippet]) -> None:
78
- """Add snippets to an index."""
79
- ...
85
+ class GitCommitRepository(ABC):
86
+ """Repository for Git commits."""
80
87
 
81
- async def update_snippets(self, index_id: int, snippets: list[Snippet]) -> None:
82
- """Update snippets for an index."""
83
- ...
88
+ @abstractmethod
89
+ async def get_by_sha(self, commit_sha: str) -> GitCommit:
90
+ """Get a commit by its SHA."""
84
91
 
85
- async def delete_snippets(self, index_id: int) -> None:
86
- """Delete all snippets from an index."""
87
- ...
92
+ @abstractmethod
93
+ async def get_by_repo_id(self, repo_id: int) -> list[GitCommit]:
94
+ """Get all commits for a repository."""
88
95
 
89
- async def delete_snippets_by_file_ids(self, file_ids: list[int]) -> None:
90
- """Delete snippets by file IDs."""
91
- ...
96
+ @abstractmethod
97
+ async def save(self, commit: GitCommit, repo_id: int) -> GitCommit:
98
+ """Save a commit to a repository."""
92
99
 
93
- async def search(self, request: MultiSearchRequest) -> Sequence[SnippetWithContext]:
94
- """Search snippets with filters."""
95
- ...
100
+ @abstractmethod
101
+ async def save_bulk(self, commits: list[GitCommit], repo_id: int) -> None:
102
+ """Bulk save commits to a repository."""
96
103
 
97
- async def get_snippets_by_ids(self, ids: list[int]) -> list[SnippetWithContext]:
98
- """Get snippets by their IDs."""
99
- ...
104
+ @abstractmethod
105
+ async def exists(self, commit_sha: str) -> bool:
106
+ """Check if a commit exists."""
100
107
 
108
+ @abstractmethod
109
+ async def delete_by_repo_id(self, repo_id: int) -> None:
110
+ """Delete all commits for a repository."""
101
111
 
102
- class ReportingModule(Protocol):
103
- """Reporting module."""
112
+ @abstractmethod
113
+ async def count_by_repo_id(self, repo_id: int) -> int:
114
+ """Count the number of commits for a repository."""
104
115
 
105
- async def on_change(self, progress: TaskStatus) -> None:
106
- """On step changed."""
107
- ...
108
116
 
117
+ class GitBranchRepository(ABC):
118
+ """Repository for Git branches."""
109
119
 
110
- class TaskStatusRepository(Protocol):
111
- """Repository interface for persisting progress state only."""
120
+ @abstractmethod
121
+ async def get_by_name(self, branch_name: str, repo_id: int) -> GitBranch:
122
+ """Get a branch by name and repository ID."""
112
123
 
113
- async def save(self, status: TaskStatus) -> None:
114
- """Save a progress state."""
115
- ...
124
+ @abstractmethod
125
+ async def get_by_repo_id(self, repo_id: int) -> list[GitBranch]:
126
+ """Get all branches for a repository."""
116
127
 
117
- async def load_with_hierarchy(
118
- self, trackable_type: str, trackable_id: int
119
- ) -> list[TaskStatus]:
120
- """Load progress states with IDs and parent IDs from database."""
121
- ...
128
+ @abstractmethod
129
+ async def save(self, branch: GitBranch, repo_id: int) -> GitBranch:
130
+ """Save a branch to a repository."""
122
131
 
123
- async def delete(self, status: TaskStatus) -> None:
124
- """Delete a progress state."""
125
- ...
132
+ @abstractmethod
133
+ async def save_bulk(self, branches: list[GitBranch], repo_id: int) -> None:
134
+ """Bulk save branches to a repository."""
135
+
136
+ @abstractmethod
137
+ async def exists(self, branch_name: str, repo_id: int) -> bool:
138
+ """Check if a branch exists."""
139
+
140
+ @abstractmethod
141
+ async def delete_by_repo_id(self, repo_id: int) -> None:
142
+ """Delete all branches for a repository."""
143
+
144
+ @abstractmethod
145
+ async def count_by_repo_id(self, repo_id: int) -> int:
146
+ """Count the number of branches for a repository."""
147
+
148
+
149
+ class GitTagRepository(ABC):
150
+ """Repository for Git tags."""
151
+
152
+ @abstractmethod
153
+ async def get_by_name(self, tag_name: str, repo_id: int) -> GitTag:
154
+ """Get a tag by name and repository ID."""
155
+
156
+ @abstractmethod
157
+ async def get_by_repo_id(self, repo_id: int) -> list[GitTag]:
158
+ """Get all tags for a repository."""
159
+
160
+ @abstractmethod
161
+ async def save(self, tag: GitTag, repo_id: int) -> GitTag:
162
+ """Save a tag to a repository."""
163
+
164
+ @abstractmethod
165
+ async def save_bulk(self, tags: list[GitTag], repo_id: int) -> None:
166
+ """Bulk save tags to a repository."""
167
+
168
+ @abstractmethod
169
+ async def exists(self, tag_name: str, repo_id: int) -> bool:
170
+ """Check if a tag exists."""
171
+
172
+ @abstractmethod
173
+ async def delete_by_repo_id(self, repo_id: int) -> None:
174
+ """Delete all tags for a repository."""
175
+
176
+ @abstractmethod
177
+ async def count_by_repo_id(self, repo_id: int) -> int:
178
+ """Count the number of tags for a repository."""
179
+
180
+
181
+ class GitRepoRepository(ABC):
182
+ """Repository pattern for GitRepo aggregate.
183
+
184
+ GitRepo is the aggregate root that owns branches, commits, and tags.
185
+ This repository handles persistence of the entire aggregate.
186
+ """
187
+
188
+ @abstractmethod
189
+ async def save(self, repo: GitRepo) -> GitRepo:
190
+ """Save or update a repository with all its branches, commits, and tags.
191
+
192
+ This method persists the entire aggregate:
193
+ - The GitRepo entity itself
194
+ - All associated branches
195
+ - All associated commits
196
+ - All associated tags
197
+ """
198
+
199
+ @abstractmethod
200
+ async def get_by_id(self, repo_id: int) -> GitRepo:
201
+ """Get repository by ID with all associated data."""
202
+
203
+ @abstractmethod
204
+ async def get_by_uri(self, sanitized_uri: AnyUrl) -> GitRepo:
205
+ """Get repository by sanitized URI with all associated data."""
206
+
207
+ @abstractmethod
208
+ async def get_by_commit(self, commit_sha: str) -> GitRepo:
209
+ """Get repository by commit SHA with all associated data."""
210
+
211
+ @abstractmethod
212
+ async def get_all(self) -> list[GitRepo]:
213
+ """Get all repositories."""
214
+
215
+ @abstractmethod
216
+ async def delete(self, sanitized_uri: AnyUrl) -> bool:
217
+ """Delete a repository."""
218
+
219
+
220
+ class GitAdapter(ABC):
221
+ """Abstract interface for Git operations."""
222
+
223
+ @abstractmethod
224
+ async def clone_repository(self, remote_uri: str, local_path: Path) -> None:
225
+ """Clone a repository to local path."""
226
+
227
+ @abstractmethod
228
+ async def pull_repository(self, local_path: Path) -> None:
229
+ """Pull latest changes for existing repository."""
230
+
231
+ @abstractmethod
232
+ async def get_all_branches(self, local_path: Path) -> list[dict[str, Any]]:
233
+ """Get all branches in repository."""
234
+
235
+ @abstractmethod
236
+ async def get_branch_commits(
237
+ self, local_path: Path, branch_name: str
238
+ ) -> list[dict[str, Any]]:
239
+ """Get commit history for a specific branch."""
240
+
241
+ @abstractmethod
242
+ async def get_commit_files(
243
+ self, local_path: Path, commit_sha: str
244
+ ) -> list[dict[str, Any]]:
245
+ """Get all files in a specific commit from the git tree."""
246
+
247
+ @abstractmethod
248
+ async def get_commit_file_data(
249
+ self, local_path: Path, commit_sha: str
250
+ ) -> list[dict[str, Any]]:
251
+ """Get file metadata for a commit, with files checked out to disk."""
252
+
253
+ @abstractmethod
254
+ async def repository_exists(self, local_path: Path) -> bool:
255
+ """Check if repository exists at local path."""
256
+
257
+ @abstractmethod
258
+ async def get_commit_details(
259
+ self, local_path: Path, commit_sha: str
260
+ ) -> dict[str, Any]:
261
+ """Get details of a specific commit."""
262
+
263
+ @abstractmethod
264
+ async def ensure_repository(self, remote_uri: str, local_path: Path) -> None:
265
+ """Ensure repository exists at local path."""
266
+
267
+ @abstractmethod
268
+ async def get_file_content(
269
+ self, local_path: Path, commit_sha: str, file_path: str
270
+ ) -> bytes:
271
+ """Get file content at specific commit."""
272
+
273
+ @abstractmethod
274
+ async def get_latest_commit_sha(
275
+ self, local_path: Path, branch_name: str = "HEAD"
276
+ ) -> str:
277
+ """Get the latest commit SHA for a branch."""
278
+
279
+ @abstractmethod
280
+ async def get_all_tags(self, local_path: Path) -> list[dict[str, Any]]:
281
+ """Get all tags in repository."""
282
+
283
+ @abstractmethod
284
+ async def get_all_commits_bulk(self, local_path: Path) -> dict[str, dict[str, Any]]:
285
+ """Get all commits from all branches in bulk for efficiency."""
286
+
287
+ @abstractmethod
288
+ async def get_branch_commit_shas(
289
+ self, local_path: Path, branch_name: str
290
+ ) -> list[str]:
291
+ """Get only commit SHAs for a branch (much faster than full commit data)."""
292
+
293
+
294
+ class SnippetRepositoryV2(ABC):
295
+ """Repository for snippet operations."""
296
+
297
+ @abstractmethod
298
+ async def save_snippets(self, commit_sha: str, snippets: list[SnippetV2]) -> None:
299
+ """Batch save snippets for a commit."""
300
+
301
+ @abstractmethod
302
+ async def get_snippets_for_commit(self, commit_sha: str) -> list[SnippetV2]:
303
+ """Get all snippets for a specific commit."""
304
+
305
+ @abstractmethod
306
+ async def delete_snippets_for_commit(self, commit_sha: str) -> None:
307
+ """Delete all snippet associations for a commit."""
308
+
309
+ @abstractmethod
310
+ async def search(self, request: MultiSearchRequest) -> list[SnippetV2]:
311
+ """Search snippets with filters."""
312
+
313
+ @abstractmethod
314
+ async def get_by_ids(self, ids: list[str]) -> list[SnippetV2]:
315
+ """Get snippets by their IDs."""
316
+
317
+
318
+ class FusionService(ABC):
319
+ """Abstract fusion service interface."""
320
+
321
+ @abstractmethod
322
+ def reciprocal_rank_fusion(
323
+ self, rankings: list[list[FusionRequest]], k: float = 60
324
+ ) -> list[FusionResult]:
325
+ """Perform reciprocal rank fusion on search results."""
@@ -105,7 +105,11 @@ class BM25DomainService:
105
105
  valid_ids = [
106
106
  snippet_id
107
107
  for snippet_id in request.snippet_ids
108
- if snippet_id is not None and snippet_id > 0
108
+ if (
109
+ snippet_id is not None
110
+ and snippet_id != "0"
111
+ and not snippet_id.startswith("-")
112
+ )
109
113
  ]
110
114
 
111
115
  if not valid_ids:
@@ -91,6 +91,9 @@ class EmbeddingDomainService:
91
91
  if not valid_documents:
92
92
  return
93
93
 
94
+ # TODO(Phil): We should handle the embedding of the documents here, then use the
95
+ # repo to simply store the embeddings.
96
+
94
97
  # Domain logic: create new request with validated documents
95
98
  validated_request = IndexRequest(documents=valid_documents)
96
99
  async for result in self.vector_search_repository.index_documents(
@@ -1,48 +1,27 @@
1
1
  """Domain service for enrichment operations."""
2
2
 
3
- from abc import ABC, abstractmethod
4
3
  from collections.abc import AsyncGenerator
5
4
 
6
- from kodit.domain.value_objects import (
7
- EnrichmentIndexRequest,
8
- EnrichmentRequest,
9
- EnrichmentResponse,
10
- )
11
-
12
-
13
- class EnrichmentProvider(ABC):
14
- """Abstract enrichment provider interface."""
15
-
16
- @abstractmethod
17
- def enrich(
18
- self, requests: list[EnrichmentRequest]
19
- ) -> AsyncGenerator[EnrichmentResponse, None]:
20
- """Enrich a list of requests."""
5
+ from kodit.domain.enrichments.enricher import Enricher
6
+ from kodit.domain.enrichments.request import EnrichmentRequest
7
+ from kodit.domain.enrichments.response import EnrichmentResponse
21
8
 
22
9
 
23
10
  class EnrichmentDomainService:
24
11
  """Domain service for enrichment operations."""
25
12
 
26
- def __init__(self, enrichment_provider: EnrichmentProvider) -> None:
27
- """Initialize the enrichment domain service.
28
-
29
- Args:
30
- enrichment_provider: The enrichment provider to use.
31
-
32
- """
33
- self.enrichment_provider = enrichment_provider
13
+ def __init__(self, enricher: Enricher) -> None:
14
+ """Initialize the enrichment domain service."""
15
+ self.enricher = enricher
34
16
 
35
17
  async def enrich_documents(
36
- self, request: EnrichmentIndexRequest
18
+ self, requests: list[EnrichmentRequest]
37
19
  ) -> AsyncGenerator[EnrichmentResponse, None]:
38
- """Enrich documents using the enrichment provider.
39
-
40
- Args:
41
- request: The enrichment index request.
20
+ """Enrich documents using the enricher.
42
21
 
43
22
  Yields:
44
23
  Enrichment responses as they are processed.
45
24
 
46
25
  """
47
- async for response in self.enrichment_provider.enrich(request.requests):
26
+ async for response in self.enricher.enrich(requests):
48
27
  yield response