julee 0.1.1__py3-none-any.whl → 0.1.3__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.
- julee/api/app.py +9 -8
- julee/api/dependencies.py +15 -15
- julee/api/requests.py +10 -9
- julee/api/responses.py +2 -1
- julee/api/routers/__init__.py +5 -5
- julee/api/routers/assembly_specifications.py +5 -4
- julee/api/routers/documents.py +1 -1
- julee/api/routers/knowledge_service_configs.py +4 -3
- julee/api/routers/knowledge_service_queries.py +7 -6
- julee/api/routers/system.py +4 -3
- julee/api/routers/workflows.py +4 -5
- julee/api/services/system_initialization.py +6 -6
- julee/api/tests/routers/test_assembly_specifications.py +4 -3
- julee/api/tests/routers/test_documents.py +5 -4
- julee/api/tests/routers/test_knowledge_service_configs.py +7 -6
- julee/api/tests/routers/test_knowledge_service_queries.py +4 -3
- julee/api/tests/routers/test_system.py +5 -4
- julee/api/tests/routers/test_workflows.py +5 -4
- julee/api/tests/test_app.py +5 -4
- julee/api/tests/test_dependencies.py +3 -2
- julee/api/tests/test_requests.py +2 -1
- julee/contrib/__init__.py +15 -0
- julee/contrib/polling/__init__.py +47 -0
- julee/contrib/polling/domain/__init__.py +17 -0
- julee/contrib/polling/domain/models/__init__.py +13 -0
- julee/contrib/polling/domain/models/polling_config.py +39 -0
- julee/contrib/polling/domain/services/__init__.py +11 -0
- julee/contrib/polling/domain/services/poller.py +39 -0
- julee/contrib/polling/infrastructure/__init__.py +15 -0
- julee/contrib/polling/infrastructure/services/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/http/__init__.py +12 -0
- julee/contrib/polling/infrastructure/services/polling/http/http_poller_service.py +80 -0
- julee/contrib/polling/infrastructure/temporal/__init__.py +20 -0
- julee/contrib/polling/infrastructure/temporal/activities.py +42 -0
- julee/contrib/polling/infrastructure/temporal/activity_names.py +20 -0
- julee/contrib/polling/infrastructure/temporal/proxies.py +45 -0
- julee/contrib/polling/tests/__init__.py +6 -0
- julee/contrib/polling/tests/unit/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/__init__.py +7 -0
- julee/contrib/polling/tests/unit/infrastructure/services/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/__init__.py +6 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/http/__init__.py +7 -0
- julee/contrib/polling/tests/unit/infrastructure/services/polling/http/test_http_poller_service.py +163 -0
- julee/docs/__init__.py +5 -0
- julee/docs/sphinx_hcd/__init__.py +82 -0
- julee/docs/sphinx_hcd/accelerators.py +1078 -0
- julee/docs/sphinx_hcd/apps.py +499 -0
- julee/docs/sphinx_hcd/config.py +148 -0
- julee/docs/sphinx_hcd/epics.py +448 -0
- julee/docs/sphinx_hcd/integrations.py +306 -0
- julee/docs/sphinx_hcd/journeys.py +783 -0
- julee/docs/sphinx_hcd/personas.py +435 -0
- julee/docs/sphinx_hcd/stories.py +932 -0
- julee/docs/sphinx_hcd/utils.py +180 -0
- julee/domain/models/__init__.py +5 -6
- julee/domain/models/assembly/assembly.py +7 -7
- julee/domain/models/assembly/tests/factories.py +2 -1
- julee/domain/models/assembly/tests/test_assembly.py +16 -13
- julee/domain/models/assembly_specification/assembly_specification.py +11 -10
- julee/domain/models/assembly_specification/knowledge_service_query.py +14 -9
- julee/domain/models/assembly_specification/tests/factories.py +2 -1
- julee/domain/models/assembly_specification/tests/test_assembly_specification.py +9 -6
- julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +3 -1
- julee/domain/models/custom_fields/content_stream.py +3 -2
- julee/domain/models/custom_fields/tests/test_custom_fields.py +2 -1
- julee/domain/models/document/document.py +12 -10
- julee/domain/models/document/tests/factories.py +3 -2
- julee/domain/models/document/tests/test_document.py +6 -3
- julee/domain/models/knowledge_service_config/knowledge_service_config.py +4 -4
- julee/domain/models/policy/__init__.py +4 -4
- julee/domain/models/policy/document_policy_validation.py +17 -17
- julee/domain/models/policy/policy.py +12 -10
- julee/domain/models/policy/tests/factories.py +2 -1
- julee/domain/models/policy/tests/test_document_policy_validation.py +3 -1
- julee/domain/models/policy/tests/test_policy.py +2 -1
- julee/domain/repositories/__init__.py +3 -3
- julee/domain/repositories/assembly.py +3 -1
- julee/domain/repositories/assembly_specification.py +2 -0
- julee/domain/repositories/base.py +33 -16
- julee/domain/repositories/document.py +3 -1
- julee/domain/repositories/document_policy_validation.py +3 -1
- julee/domain/repositories/knowledge_service_config.py +2 -0
- julee/domain/repositories/knowledge_service_query.py +1 -0
- julee/domain/repositories/policy.py +3 -1
- julee/domain/use_cases/decorators.py +3 -2
- julee/domain/use_cases/extract_assemble_data.py +23 -13
- julee/domain/use_cases/initialize_system_data.py +13 -13
- julee/domain/use_cases/tests/test_extract_assemble_data.py +10 -10
- julee/domain/use_cases/tests/test_initialize_system_data.py +2 -2
- julee/domain/use_cases/tests/test_validate_document.py +11 -11
- julee/domain/use_cases/validate_document.py +26 -15
- julee/maintenance/__init__.py +1 -0
- julee/maintenance/release.py +188 -0
- julee/repositories/__init__.py +4 -1
- julee/repositories/memory/assembly.py +6 -5
- julee/repositories/memory/assembly_specification.py +9 -9
- julee/repositories/memory/base.py +12 -11
- julee/repositories/memory/document.py +8 -7
- julee/repositories/memory/document_policy_validation.py +7 -6
- julee/repositories/memory/knowledge_service_config.py +9 -7
- julee/repositories/memory/knowledge_service_query.py +9 -7
- julee/repositories/memory/policy.py +6 -5
- julee/repositories/memory/tests/test_document.py +6 -4
- julee/repositories/memory/tests/test_document_policy_validation.py +2 -1
- julee/repositories/memory/tests/test_policy.py +2 -1
- julee/repositories/minio/assembly.py +4 -4
- julee/repositories/minio/assembly_specification.py +6 -8
- julee/repositories/minio/client.py +22 -25
- julee/repositories/minio/document.py +11 -11
- julee/repositories/minio/document_policy_validation.py +5 -5
- julee/repositories/minio/knowledge_service_config.py +8 -8
- julee/repositories/minio/knowledge_service_query.py +6 -9
- julee/repositories/minio/policy.py +4 -4
- julee/repositories/minio/tests/fake_client.py +11 -9
- julee/repositories/minio/tests/test_assembly.py +3 -1
- julee/repositories/minio/tests/test_assembly_specification.py +2 -1
- julee/repositories/minio/tests/test_client_protocol.py +5 -5
- julee/repositories/minio/tests/test_document.py +7 -6
- julee/repositories/minio/tests/test_document_policy_validation.py +3 -1
- julee/repositories/minio/tests/test_knowledge_service_config.py +4 -2
- julee/repositories/minio/tests/test_knowledge_service_query.py +3 -2
- julee/repositories/minio/tests/test_policy.py +3 -1
- julee/repositories/temporal/activities.py +5 -5
- julee/repositories/temporal/proxies.py +5 -5
- julee/services/knowledge_service/__init__.py +1 -2
- julee/services/knowledge_service/anthropic/knowledge_service.py +8 -7
- julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +11 -10
- julee/services/knowledge_service/factory.py +8 -8
- julee/services/knowledge_service/knowledge_service.py +22 -18
- julee/services/knowledge_service/memory/knowledge_service.py +13 -12
- julee/services/knowledge_service/memory/test_knowledge_service.py +10 -7
- julee/services/knowledge_service/test_factory.py +11 -10
- julee/services/temporal/activities.py +10 -10
- julee/services/temporal/proxies.py +2 -2
- julee/util/domain.py +6 -6
- julee/util/repos/minio/file_storage.py +8 -9
- julee/util/repos/temporal/client_proxies/file_storage.py +3 -4
- julee/util/repos/temporal/data_converter.py +6 -6
- julee/util/repos/temporal/minio_file_storage.py +1 -1
- julee/util/repos/temporal/proxies/file_storage.py +2 -3
- julee/util/repositories.py +6 -7
- julee/util/temporal/activities.py +1 -1
- julee/util/temporal/decorators.py +28 -33
- julee/util/tests/test_decorators.py +13 -15
- julee/util/validation/repository.py +3 -3
- julee/util/validation/type_guards.py +12 -11
- julee/worker.py +9 -8
- julee/workflows/__init__.py +2 -2
- julee/workflows/extract_assemble.py +2 -1
- julee/workflows/validate_document.py +3 -2
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/METADATA +4 -1
- julee-0.1.3.dist-info/RECORD +197 -0
- julee-0.1.1.dist-info/RECORD +0 -161
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/WHEEL +0 -0
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {julee-0.1.1.dist-info → julee-0.1.3.dist-info}/top_level.txt +0 -0
|
@@ -10,8 +10,9 @@ instances following the Clean Architecture principles.
|
|
|
10
10
|
import hashlib
|
|
11
11
|
import json
|
|
12
12
|
import logging
|
|
13
|
+
from collections.abc import Callable
|
|
13
14
|
from datetime import datetime, timezone
|
|
14
|
-
from typing import Any
|
|
15
|
+
from typing import Any
|
|
15
16
|
|
|
16
17
|
import jsonpointer # type: ignore
|
|
17
18
|
import jsonschema
|
|
@@ -57,6 +58,7 @@ class ExtractAssembleDataUseCase:
|
|
|
57
58
|
methods and expects them to work correctly.
|
|
58
59
|
|
|
59
60
|
Architectural Notes:
|
|
61
|
+
|
|
60
62
|
- This class contains pure business logic with no framework dependencies
|
|
61
63
|
- Repository dependencies are injected via constructor
|
|
62
64
|
(dependency inversion)
|
|
@@ -64,6 +66,7 @@ class ExtractAssembleDataUseCase:
|
|
|
64
66
|
- The use case works with domain objects exclusively
|
|
65
67
|
- Deterministic execution is guaranteed by avoiding
|
|
66
68
|
non-deterministic operations
|
|
69
|
+
|
|
67
70
|
"""
|
|
68
71
|
|
|
69
72
|
def __init__(
|
|
@@ -91,7 +94,8 @@ class ExtractAssembleDataUseCase:
|
|
|
91
94
|
operations
|
|
92
95
|
now_fn: Function to get current time (for workflow compatibility)
|
|
93
96
|
|
|
94
|
-
|
|
97
|
+
.. note::
|
|
98
|
+
|
|
95
99
|
The repositories passed here may be concrete implementations
|
|
96
100
|
(for testing or direct execution) or workflow stubs (for
|
|
97
101
|
Temporal workflow execution). The use case doesn't know or care
|
|
@@ -99,6 +103,7 @@ class ExtractAssembleDataUseCase:
|
|
|
99
103
|
|
|
100
104
|
Repositories are validated at construction time to catch
|
|
101
105
|
configuration errors early in the application lifecycle.
|
|
106
|
+
|
|
102
107
|
"""
|
|
103
108
|
# Validate at construction time for early error detection
|
|
104
109
|
self.document_repo = ensure_repository_protocol(
|
|
@@ -135,6 +140,7 @@ class ExtractAssembleDataUseCase:
|
|
|
135
140
|
assembly.
|
|
136
141
|
|
|
137
142
|
This method orchestrates the core assembly workflow:
|
|
143
|
+
|
|
138
144
|
1. Generates a unique assembly ID
|
|
139
145
|
2. Retrieves the assembly specification
|
|
140
146
|
3. Stores the initial assembly in the repository
|
|
@@ -156,6 +162,7 @@ class ExtractAssembleDataUseCase:
|
|
|
156
162
|
Raises:
|
|
157
163
|
ValueError: If required entities are not found or invalid
|
|
158
164
|
RuntimeError: If assembly processing fails
|
|
165
|
+
|
|
159
166
|
"""
|
|
160
167
|
logger.debug(
|
|
161
168
|
"Starting data assembly use case",
|
|
@@ -250,8 +257,8 @@ class ExtractAssembleDataUseCase:
|
|
|
250
257
|
async def _register_document_with_services(
|
|
251
258
|
self,
|
|
252
259
|
document: Document,
|
|
253
|
-
queries:
|
|
254
|
-
) ->
|
|
260
|
+
queries: dict[str, KnowledgeServiceQuery],
|
|
261
|
+
) -> dict[str, str]:
|
|
255
262
|
"""
|
|
256
263
|
Register the document with all knowledge services needed for assembly.
|
|
257
264
|
|
|
@@ -267,6 +274,7 @@ class ExtractAssembleDataUseCase:
|
|
|
267
274
|
|
|
268
275
|
Raises:
|
|
269
276
|
RuntimeError: If registration fails
|
|
277
|
+
|
|
270
278
|
"""
|
|
271
279
|
registrations = {}
|
|
272
280
|
|
|
@@ -294,7 +302,7 @@ class ExtractAssembleDataUseCase:
|
|
|
294
302
|
@try_use_case_step("queries_retrieval")
|
|
295
303
|
async def _retrieve_all_queries(
|
|
296
304
|
self, assembly_specification: AssemblySpecification
|
|
297
|
-
) ->
|
|
305
|
+
) -> dict[str, KnowledgeServiceQuery]:
|
|
298
306
|
"""Retrieve all knowledge service queries needed for this assembly."""
|
|
299
307
|
query_ids = list(assembly_specification.knowledge_service_queries.values())
|
|
300
308
|
|
|
@@ -344,13 +352,14 @@ class ExtractAssembleDataUseCase:
|
|
|
344
352
|
self,
|
|
345
353
|
document: Document,
|
|
346
354
|
assembly_specification: AssemblySpecification,
|
|
347
|
-
document_registrations:
|
|
348
|
-
queries:
|
|
355
|
+
document_registrations: dict[str, str],
|
|
356
|
+
queries: dict[str, KnowledgeServiceQuery],
|
|
349
357
|
) -> str:
|
|
350
358
|
"""
|
|
351
359
|
Perform a single assembly iteration using knowledge services.
|
|
352
360
|
|
|
353
361
|
This method:
|
|
362
|
+
|
|
354
363
|
1. Executes all knowledge service queries defined in the specification
|
|
355
364
|
2. Stitches together the query results into a complete JSON document
|
|
356
365
|
3. Creates and stores the assembled document
|
|
@@ -368,9 +377,10 @@ class ExtractAssembleDataUseCase:
|
|
|
368
377
|
Raises:
|
|
369
378
|
ValueError: If required entities are not found
|
|
370
379
|
RuntimeError: If knowledge service operations fail
|
|
380
|
+
|
|
371
381
|
"""
|
|
372
382
|
# Initialize the result data structure
|
|
373
|
-
assembled_data:
|
|
383
|
+
assembled_data: dict[str, Any] = {}
|
|
374
384
|
|
|
375
385
|
# Process each knowledge service query
|
|
376
386
|
# TODO: This is where we may want to fan-out/fan-in to do these
|
|
@@ -461,7 +471,7 @@ class ExtractAssembleDataUseCase:
|
|
|
461
471
|
return document
|
|
462
472
|
|
|
463
473
|
def _extract_schema_section(
|
|
464
|
-
self, jsonschema:
|
|
474
|
+
self, jsonschema: dict[str, Any], schema_pointer: str
|
|
465
475
|
) -> Any:
|
|
466
476
|
"""Extract relevant section of JSON schema using JSON Pointer."""
|
|
467
477
|
if not schema_pointer:
|
|
@@ -486,7 +496,7 @@ Please structure your response according to this JSON schema:
|
|
|
486
496
|
Return only valid JSON that conforms to this schema, without any surrounding
|
|
487
497
|
text or markdown formatting."""
|
|
488
498
|
|
|
489
|
-
def _parse_query_result(self, result_data:
|
|
499
|
+
def _parse_query_result(self, result_data: dict[str, Any]) -> Any:
|
|
490
500
|
"""Parse the query result to extract the JSON response."""
|
|
491
501
|
response_text = result_data.get("response", "")
|
|
492
502
|
if not response_text:
|
|
@@ -505,7 +515,7 @@ text or markdown formatting."""
|
|
|
505
515
|
|
|
506
516
|
def _store_result_in_assembled_data(
|
|
507
517
|
self,
|
|
508
|
-
assembled_data:
|
|
518
|
+
assembled_data: dict[str, Any],
|
|
509
519
|
schema_pointer: str,
|
|
510
520
|
result_data: Any,
|
|
511
521
|
) -> None:
|
|
@@ -563,7 +573,7 @@ text or markdown formatting."""
|
|
|
563
573
|
@try_use_case_step("assembled_document_creation")
|
|
564
574
|
async def _create_assembled_document(
|
|
565
575
|
self,
|
|
566
|
-
assembled_data:
|
|
576
|
+
assembled_data: dict[str, Any],
|
|
567
577
|
assembly_specification: AssemblySpecification,
|
|
568
578
|
) -> str:
|
|
569
579
|
"""Create and store the assembled document."""
|
|
@@ -596,7 +606,7 @@ text or markdown formatting."""
|
|
|
596
606
|
|
|
597
607
|
def _validate_assembled_data(
|
|
598
608
|
self,
|
|
599
|
-
assembled_data:
|
|
609
|
+
assembled_data: dict[str, Any],
|
|
600
610
|
assembly_specification: AssemblySpecification,
|
|
601
611
|
) -> None:
|
|
602
612
|
"""Validate that the assembled data conforms to the JSON schema."""
|
|
@@ -16,7 +16,7 @@ import hashlib
|
|
|
16
16
|
import logging
|
|
17
17
|
from datetime import datetime, timezone
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import Any
|
|
19
|
+
from typing import Any
|
|
20
20
|
|
|
21
21
|
import yaml
|
|
22
22
|
|
|
@@ -192,7 +192,7 @@ class InitializeSystemDataUseCase:
|
|
|
192
192
|
)
|
|
193
193
|
raise
|
|
194
194
|
|
|
195
|
-
def _load_fixture_configurations(self) ->
|
|
195
|
+
def _load_fixture_configurations(self) -> list[dict[str, Any]]:
|
|
196
196
|
"""
|
|
197
197
|
Load knowledge service configurations from the YAML fixture file.
|
|
198
198
|
|
|
@@ -217,7 +217,7 @@ class InitializeSystemDataUseCase:
|
|
|
217
217
|
)
|
|
218
218
|
|
|
219
219
|
try:
|
|
220
|
-
with open(fixture_path,
|
|
220
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
221
221
|
fixture_data = yaml.safe_load(f)
|
|
222
222
|
|
|
223
223
|
if not fixture_data or "knowledge_services" not in fixture_data:
|
|
@@ -240,7 +240,7 @@ class InitializeSystemDataUseCase:
|
|
|
240
240
|
raise yaml.YAMLError(f"Invalid YAML in fixture file: {e}")
|
|
241
241
|
|
|
242
242
|
def _create_config_from_fixture_data(
|
|
243
|
-
self, config_data:
|
|
243
|
+
self, config_data: dict[str, Any]
|
|
244
244
|
) -> KnowledgeServiceConfig:
|
|
245
245
|
"""
|
|
246
246
|
Create a KnowledgeServiceConfig from fixture data.
|
|
@@ -363,7 +363,7 @@ class InitializeSystemDataUseCase:
|
|
|
363
363
|
)
|
|
364
364
|
raise
|
|
365
365
|
|
|
366
|
-
def _load_fixture_queries(self) ->
|
|
366
|
+
def _load_fixture_queries(self) -> list[dict[str, Any]]:
|
|
367
367
|
"""
|
|
368
368
|
Load knowledge service queries from the YAML fixture file.
|
|
369
369
|
|
|
@@ -388,7 +388,7 @@ class InitializeSystemDataUseCase:
|
|
|
388
388
|
)
|
|
389
389
|
|
|
390
390
|
try:
|
|
391
|
-
with open(fixture_path,
|
|
391
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
392
392
|
fixture_data = yaml.safe_load(f)
|
|
393
393
|
|
|
394
394
|
if not fixture_data or "knowledge_service_queries" not in fixture_data:
|
|
@@ -413,7 +413,7 @@ class InitializeSystemDataUseCase:
|
|
|
413
413
|
raise yaml.YAMLError(f"Invalid YAML in queries fixture file: {e}")
|
|
414
414
|
|
|
415
415
|
def _create_query_from_fixture_data(
|
|
416
|
-
self, query_data:
|
|
416
|
+
self, query_data: dict[str, Any]
|
|
417
417
|
) -> KnowledgeServiceQuery:
|
|
418
418
|
"""
|
|
419
419
|
Create a KnowledgeServiceQuery from fixture data.
|
|
@@ -533,7 +533,7 @@ class InitializeSystemDataUseCase:
|
|
|
533
533
|
)
|
|
534
534
|
raise
|
|
535
535
|
|
|
536
|
-
def _load_fixture_assembly_specifications(self) ->
|
|
536
|
+
def _load_fixture_assembly_specifications(self) -> list[dict[str, Any]]:
|
|
537
537
|
"""
|
|
538
538
|
Load assembly specifications from the YAML fixture file.
|
|
539
539
|
|
|
@@ -558,7 +558,7 @@ class InitializeSystemDataUseCase:
|
|
|
558
558
|
)
|
|
559
559
|
|
|
560
560
|
try:
|
|
561
|
-
with open(fixture_path,
|
|
561
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
562
562
|
fixture_data = yaml.safe_load(f)
|
|
563
563
|
|
|
564
564
|
if not fixture_data or "assembly_specifications" not in fixture_data:
|
|
@@ -586,7 +586,7 @@ class InitializeSystemDataUseCase:
|
|
|
586
586
|
)
|
|
587
587
|
|
|
588
588
|
def _create_assembly_spec_from_fixture_data(
|
|
589
|
-
self, spec_data:
|
|
589
|
+
self, spec_data: dict[str, Any]
|
|
590
590
|
) -> AssemblySpecification:
|
|
591
591
|
"""
|
|
592
592
|
Create an AssemblySpecification from fixture data.
|
|
@@ -719,7 +719,7 @@ class InitializeSystemDataUseCase:
|
|
|
719
719
|
)
|
|
720
720
|
raise
|
|
721
721
|
|
|
722
|
-
def _load_fixture_documents(self) ->
|
|
722
|
+
def _load_fixture_documents(self) -> list[dict[str, Any]]:
|
|
723
723
|
"""
|
|
724
724
|
Load documents from the YAML fixture file.
|
|
725
725
|
|
|
@@ -742,7 +742,7 @@ class InitializeSystemDataUseCase:
|
|
|
742
742
|
raise FileNotFoundError(f"Documents fixture file not found: {fixture_path}")
|
|
743
743
|
|
|
744
744
|
try:
|
|
745
|
-
with open(fixture_path,
|
|
745
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
746
746
|
fixture_data = yaml.safe_load(f)
|
|
747
747
|
|
|
748
748
|
if not fixture_data or "documents" not in fixture_data:
|
|
@@ -764,7 +764,7 @@ class InitializeSystemDataUseCase:
|
|
|
764
764
|
except yaml.YAMLError as e:
|
|
765
765
|
raise yaml.YAMLError(f"Invalid YAML in documents fixture file: {e}")
|
|
766
766
|
|
|
767
|
-
def _create_document_from_fixture_data(self, doc_data:
|
|
767
|
+
def _create_document_from_fixture_data(self, doc_data: dict[str, Any]) -> Document:
|
|
768
768
|
"""
|
|
769
769
|
Create a Document from fixture data.
|
|
770
770
|
|
|
@@ -8,35 +8,35 @@ following the Clean Architecture principles.
|
|
|
8
8
|
|
|
9
9
|
import io
|
|
10
10
|
import json
|
|
11
|
-
import pytest
|
|
12
|
-
|
|
13
|
-
from unittest.mock import AsyncMock
|
|
14
11
|
from datetime import datetime, timezone
|
|
12
|
+
from unittest.mock import AsyncMock
|
|
13
|
+
|
|
14
|
+
import pytest
|
|
15
15
|
|
|
16
|
-
from julee.domain.use_cases import ExtractAssembleDataUseCase
|
|
17
16
|
from julee.domain.models import (
|
|
18
17
|
Assembly,
|
|
18
|
+
AssemblySpecification,
|
|
19
|
+
AssemblySpecificationStatus,
|
|
19
20
|
AssemblyStatus,
|
|
21
|
+
ContentStream,
|
|
20
22
|
Document,
|
|
21
23
|
DocumentStatus,
|
|
22
|
-
ContentStream,
|
|
23
|
-
AssemblySpecification,
|
|
24
|
-
AssemblySpecificationStatus,
|
|
25
|
-
KnowledgeServiceQuery,
|
|
26
24
|
KnowledgeServiceConfig,
|
|
25
|
+
KnowledgeServiceQuery,
|
|
27
26
|
)
|
|
28
27
|
from julee.domain.models.knowledge_service_config import ServiceApi
|
|
28
|
+
from julee.domain.use_cases import ExtractAssembleDataUseCase
|
|
29
29
|
from julee.repositories.memory import (
|
|
30
|
-
MemoryDocumentRepository,
|
|
31
30
|
MemoryAssemblyRepository,
|
|
32
31
|
MemoryAssemblySpecificationRepository,
|
|
32
|
+
MemoryDocumentRepository,
|
|
33
33
|
MemoryKnowledgeServiceConfigRepository,
|
|
34
34
|
MemoryKnowledgeServiceQueryRepository,
|
|
35
35
|
)
|
|
36
|
+
from julee.services.knowledge_service import QueryResult
|
|
36
37
|
from julee.services.knowledge_service.memory import (
|
|
37
38
|
MemoryKnowledgeService,
|
|
38
39
|
)
|
|
39
|
-
from julee.services.knowledge_service import QueryResult
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class TestExtractAssembleDataUseCase:
|
|
@@ -86,7 +86,7 @@ def fixture_configs() -> list[dict]:
|
|
|
86
86
|
|
|
87
87
|
assert fixture_path.exists(), f"Fixture file not found: {fixture_path}"
|
|
88
88
|
|
|
89
|
-
with open(fixture_path,
|
|
89
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
90
90
|
fixture_data = yaml.safe_load(f)
|
|
91
91
|
|
|
92
92
|
assert "knowledge_services" in fixture_data
|
|
@@ -320,7 +320,7 @@ class TestYamlFixtureIntegration:
|
|
|
320
320
|
assert fixture_path.exists(), f"Fixture file not found: {fixture_path}"
|
|
321
321
|
|
|
322
322
|
# Verify file can be parsed
|
|
323
|
-
with open(fixture_path,
|
|
323
|
+
with open(fixture_path, encoding="utf-8") as f:
|
|
324
324
|
fixture_data = yaml.safe_load(f)
|
|
325
325
|
|
|
326
326
|
# Verify structure
|
|
@@ -7,38 +7,38 @@ following the Clean Architecture principles.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import io
|
|
10
|
-
import pytest
|
|
11
|
-
from unittest.mock import AsyncMock
|
|
12
10
|
from datetime import datetime, timezone
|
|
13
|
-
from
|
|
11
|
+
from unittest.mock import AsyncMock
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
import pytest
|
|
14
|
+
from pydantic import ValidationError
|
|
16
15
|
|
|
17
16
|
from julee.domain.models import (
|
|
17
|
+
ContentStream,
|
|
18
18
|
Document,
|
|
19
19
|
DocumentStatus,
|
|
20
|
-
ContentStream,
|
|
21
20
|
KnowledgeServiceConfig,
|
|
22
21
|
KnowledgeServiceQuery,
|
|
23
22
|
)
|
|
23
|
+
from julee.domain.models.knowledge_service_config import ServiceApi
|
|
24
24
|
from julee.domain.models.policy import (
|
|
25
|
-
Policy,
|
|
26
|
-
PolicyStatus,
|
|
27
25
|
DocumentPolicyValidation,
|
|
28
26
|
DocumentPolicyValidationStatus,
|
|
27
|
+
Policy,
|
|
28
|
+
PolicyStatus,
|
|
29
29
|
)
|
|
30
|
-
from julee.domain.
|
|
30
|
+
from julee.domain.use_cases import ValidateDocumentUseCase
|
|
31
31
|
from julee.repositories.memory import (
|
|
32
|
+
MemoryDocumentPolicyValidationRepository,
|
|
32
33
|
MemoryDocumentRepository,
|
|
33
|
-
MemoryKnowledgeServiceQueryRepository,
|
|
34
34
|
MemoryKnowledgeServiceConfigRepository,
|
|
35
|
+
MemoryKnowledgeServiceQueryRepository,
|
|
35
36
|
MemoryPolicyRepository,
|
|
36
|
-
MemoryDocumentPolicyValidationRepository,
|
|
37
37
|
)
|
|
38
|
+
from julee.services.knowledge_service import QueryResult
|
|
38
39
|
from julee.services.knowledge_service.memory import (
|
|
39
40
|
MemoryKnowledgeService,
|
|
40
41
|
)
|
|
41
|
-
from julee.services.knowledge_service import QueryResult
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class TestValidateDocumentUseCase:
|
|
@@ -11,8 +11,8 @@ import hashlib
|
|
|
11
11
|
import io
|
|
12
12
|
import json
|
|
13
13
|
import logging
|
|
14
|
+
from collections.abc import Callable
|
|
14
15
|
from datetime import datetime
|
|
15
|
-
from typing import Callable, Dict, List, Tuple
|
|
16
16
|
|
|
17
17
|
import multihash
|
|
18
18
|
|
|
@@ -58,6 +58,7 @@ class ValidateDocumentUseCase:
|
|
|
58
58
|
methods and expects them to work correctly.
|
|
59
59
|
|
|
60
60
|
Architectural Notes:
|
|
61
|
+
|
|
61
62
|
- This class contains pure business logic with no framework dependencies
|
|
62
63
|
- Repository dependencies are injected via constructor
|
|
63
64
|
(dependency inversion)
|
|
@@ -65,6 +66,7 @@ class ValidateDocumentUseCase:
|
|
|
65
66
|
- The use case works with domain objects exclusively
|
|
66
67
|
- Deterministic execution is guaranteed by avoiding
|
|
67
68
|
non-deterministic operations
|
|
69
|
+
|
|
68
70
|
"""
|
|
69
71
|
|
|
70
72
|
def __init__(
|
|
@@ -93,7 +95,8 @@ class ValidateDocumentUseCase:
|
|
|
93
95
|
now_fn: Function to get current time (e.g., workflow.now for
|
|
94
96
|
Temporal workflows)
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
.. note::
|
|
99
|
+
|
|
97
100
|
The repositories passed here may be concrete implementations
|
|
98
101
|
(for testing or direct execution) or workflow stubs (for
|
|
99
102
|
Temporal workflow execution). The use case doesn't know or care
|
|
@@ -101,6 +104,7 @@ class ValidateDocumentUseCase:
|
|
|
101
104
|
|
|
102
105
|
Repositories are validated at construction time to catch
|
|
103
106
|
configuration errors early in the application lifecycle.
|
|
107
|
+
|
|
104
108
|
"""
|
|
105
109
|
# Validate at construction time for early error detection
|
|
106
110
|
self.document_repo = ensure_repository_protocol(
|
|
@@ -133,6 +137,7 @@ class ValidateDocumentUseCase:
|
|
|
133
137
|
Validate a document against a policy and return the validation result.
|
|
134
138
|
|
|
135
139
|
This method orchestrates the core validation workflow:
|
|
140
|
+
|
|
136
141
|
1. Generates a unique validation ID
|
|
137
142
|
2. Retrieves the document and policy
|
|
138
143
|
3. Creates and stores the initial validation record
|
|
@@ -152,6 +157,7 @@ class ValidateDocumentUseCase:
|
|
|
152
157
|
Raises:
|
|
153
158
|
ValueError: If required entities are not found or invalid
|
|
154
159
|
RuntimeError: If validation processing fails
|
|
160
|
+
|
|
155
161
|
"""
|
|
156
162
|
logger.debug(
|
|
157
163
|
"Starting document validation use case",
|
|
@@ -391,13 +397,13 @@ class ValidateDocumentUseCase:
|
|
|
391
397
|
@try_use_case_step("all_queries_retrieval")
|
|
392
398
|
async def _retrieve_all_queries(
|
|
393
399
|
self, policy: Policy
|
|
394
|
-
) ->
|
|
400
|
+
) -> dict[str, KnowledgeServiceQuery]:
|
|
395
401
|
"""Retrieve all knowledge service queries needed for validation and
|
|
396
402
|
transformation."""
|
|
397
403
|
all_queries = {}
|
|
398
404
|
|
|
399
405
|
# Get validation queries
|
|
400
|
-
for query_id,
|
|
406
|
+
for query_id, _required_score in policy.validation_scores:
|
|
401
407
|
query = await self.knowledge_service_query_repo.get(query_id)
|
|
402
408
|
if not query:
|
|
403
409
|
raise ValueError(f"Validation query not found: {query_id}")
|
|
@@ -417,8 +423,8 @@ class ValidateDocumentUseCase:
|
|
|
417
423
|
async def _register_document_with_services(
|
|
418
424
|
self,
|
|
419
425
|
document: Document,
|
|
420
|
-
queries:
|
|
421
|
-
) ->
|
|
426
|
+
queries: dict[str, KnowledgeServiceQuery],
|
|
427
|
+
) -> dict[str, str]:
|
|
422
428
|
"""
|
|
423
429
|
Register the document with all knowledge services needed for
|
|
424
430
|
validation.
|
|
@@ -429,6 +435,7 @@ class ValidateDocumentUseCase:
|
|
|
429
435
|
|
|
430
436
|
Returns:
|
|
431
437
|
Dict mapping knowledge_service_id to service_file_id
|
|
438
|
+
|
|
432
439
|
"""
|
|
433
440
|
registrations = {}
|
|
434
441
|
required_service_ids = {
|
|
@@ -457,9 +464,9 @@ class ValidateDocumentUseCase:
|
|
|
457
464
|
self,
|
|
458
465
|
document: Document,
|
|
459
466
|
policy: Policy,
|
|
460
|
-
document_registrations:
|
|
461
|
-
queries:
|
|
462
|
-
) ->
|
|
467
|
+
document_registrations: dict[str, str],
|
|
468
|
+
queries: dict[str, KnowledgeServiceQuery],
|
|
469
|
+
) -> list[tuple[str, int]]:
|
|
463
470
|
"""
|
|
464
471
|
Execute all validation queries and return the actual scores achieved.
|
|
465
472
|
|
|
@@ -471,6 +478,7 @@ class ValidateDocumentUseCase:
|
|
|
471
478
|
|
|
472
479
|
Returns:
|
|
473
480
|
List of (query_id, actual_score) tuples
|
|
481
|
+
|
|
474
482
|
"""
|
|
475
483
|
validation_scores = []
|
|
476
484
|
|
|
@@ -520,7 +528,7 @@ class ValidateDocumentUseCase:
|
|
|
520
528
|
|
|
521
529
|
return validation_scores
|
|
522
530
|
|
|
523
|
-
def _extract_score_from_result(self, result_data:
|
|
531
|
+
def _extract_score_from_result(self, result_data: dict) -> int:
|
|
524
532
|
"""
|
|
525
533
|
Extract a numeric score from the knowledge service query result.
|
|
526
534
|
|
|
@@ -543,8 +551,8 @@ class ValidateDocumentUseCase:
|
|
|
543
551
|
|
|
544
552
|
def _determine_validation_result(
|
|
545
553
|
self,
|
|
546
|
-
actual_scores:
|
|
547
|
-
required_scores:
|
|
554
|
+
actual_scores: list[tuple[str, int]],
|
|
555
|
+
required_scores: list[tuple[str, int]],
|
|
548
556
|
) -> bool:
|
|
549
557
|
"""
|
|
550
558
|
Determine if validation passed based on actual vs required scores.
|
|
@@ -556,6 +564,7 @@ class ValidateDocumentUseCase:
|
|
|
556
564
|
|
|
557
565
|
Returns:
|
|
558
566
|
True if all required scores were met or exceeded, False otherwise
|
|
567
|
+
|
|
559
568
|
"""
|
|
560
569
|
# Convert to dictionaries for easier lookup
|
|
561
570
|
actual_scores_dict = dict(actual_scores)
|
|
@@ -582,8 +591,8 @@ class ValidateDocumentUseCase:
|
|
|
582
591
|
self,
|
|
583
592
|
document: Document,
|
|
584
593
|
policy: Policy,
|
|
585
|
-
all_queries:
|
|
586
|
-
document_registrations:
|
|
594
|
+
all_queries: dict[str, KnowledgeServiceQuery],
|
|
595
|
+
document_registrations: dict[str, str],
|
|
587
596
|
) -> Document:
|
|
588
597
|
"""
|
|
589
598
|
Apply transformation queries to a document and return the
|
|
@@ -601,6 +610,7 @@ class ValidateDocumentUseCase:
|
|
|
601
610
|
Raises:
|
|
602
611
|
ValueError: If transformation queries are not found or fail
|
|
603
612
|
RuntimeError: If document transformation fails
|
|
613
|
+
|
|
604
614
|
"""
|
|
605
615
|
if not policy.transformation_queries:
|
|
606
616
|
raise ValueError("No transformation queries provided")
|
|
@@ -704,7 +714,7 @@ class ValidateDocumentUseCase:
|
|
|
704
714
|
|
|
705
715
|
return transformed_document
|
|
706
716
|
|
|
707
|
-
def _extract_transformed_content(self, result_data:
|
|
717
|
+
def _extract_transformed_content(self, result_data: dict) -> str:
|
|
708
718
|
"""
|
|
709
719
|
Extract transformed document content from knowledge service result.
|
|
710
720
|
|
|
@@ -717,6 +727,7 @@ class ValidateDocumentUseCase:
|
|
|
717
727
|
|
|
718
728
|
Raises:
|
|
719
729
|
ValueError: If no valid JSON content can be extracted from result
|
|
730
|
+
|
|
720
731
|
"""
|
|
721
732
|
response_text = result_data.get("response", "")
|
|
722
733
|
if not response_text:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Maintenance utilities for julee and julee-based solutions."""
|