digitalkin 0.3.2a2__tar.gz → 0.3.2.dev3__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.
Files changed (154) hide show
  1. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/PKG-INFO +9 -9
  2. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/pyproject.toml +108 -108
  3. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/single_job_manager.py +29 -65
  5. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/taskiq_job_manager.py +4 -8
  6. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/base_task_manager.py +1 -3
  7. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/surrealdb_repository.py +0 -6
  8. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/task_executor.py +10 -27
  9. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/task_session.py +1 -61
  10. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/module_server.py +43 -26
  11. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/module_servicer.py +14 -92
  12. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +4 -14
  13. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +4 -13
  14. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/task_monitor.py +1 -19
  15. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/models.py +8 -95
  16. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/__init__.py +4 -12
  17. digitalkin-0.3.2.dev3/src/digitalkin/models/module/module_context.py +167 -0
  18. digitalkin-0.3.2.dev3/src/digitalkin/models/module/setup_types.py +463 -0
  19. digitalkin-0.3.2.dev3/src/digitalkin/models/module/tool_reference.py +105 -0
  20. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/cost.py +1 -22
  21. digitalkin-0.3.2.dev3/src/digitalkin/models/services/registry.py +42 -0
  22. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/_base_module.py +66 -118
  23. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/communication_strategy.py +3 -14
  24. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/default_communication.py +0 -3
  25. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/grpc_communication.py +17 -58
  26. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/cost_strategy.py +14 -36
  27. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/default_cost.py +1 -61
  28. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/grpc_cost.py +1 -97
  29. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/grpc_filesystem.py +1 -8
  30. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/__init__.py +1 -1
  31. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/default_registry.py +1 -22
  32. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/grpc_registry.py +1 -77
  33. digitalkin-0.3.2.dev3/src/digitalkin/services/registry/registry_models.py +43 -0
  34. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/registry_strategy.py +1 -19
  35. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/services_config.py +4 -0
  36. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/__init__.py +3 -15
  37. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/dynamic_schema.py +0 -4
  38. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/PKG-INFO +9 -9
  39. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/SOURCES.txt +1 -11
  40. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/requires.txt +2 -2
  41. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/top_level.txt +0 -1
  42. digitalkin-0.3.2a2/examples/modules/archetype_with_tools_module.py +0 -232
  43. digitalkin-0.3.2a2/examples/monitoring/digitalkin_observability/__init__.py +0 -46
  44. digitalkin-0.3.2a2/examples/monitoring/digitalkin_observability/http_server.py +0 -150
  45. digitalkin-0.3.2a2/examples/monitoring/digitalkin_observability/interceptors.py +0 -176
  46. digitalkin-0.3.2a2/examples/monitoring/digitalkin_observability/metrics.py +0 -201
  47. digitalkin-0.3.2a2/examples/monitoring/digitalkin_observability/prometheus.py +0 -137
  48. digitalkin-0.3.2a2/examples/monitoring/tests/test_metrics.py +0 -172
  49. digitalkin-0.3.2a2/src/digitalkin/models/module/module_context.py +0 -406
  50. digitalkin-0.3.2a2/src/digitalkin/models/module/setup_types.py +0 -547
  51. digitalkin-0.3.2a2/src/digitalkin/models/module/tool_cache.py +0 -230
  52. digitalkin-0.3.2a2/src/digitalkin/models/module/tool_reference.py +0 -160
  53. digitalkin-0.3.2a2/src/digitalkin/models/services/registry.py +0 -77
  54. digitalkin-0.3.2a2/src/digitalkin/services/registry/registry_models.py +0 -15
  55. digitalkin-0.3.2a2/src/digitalkin/utils/conditional_schema.py +0 -260
  56. digitalkin-0.3.2a2/src/digitalkin/utils/schema_splitter.py +0 -290
  57. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/LICENSE +0 -0
  58. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/README.md +0 -0
  59. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/__init__.py +0 -0
  60. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/__init__.py +0 -0
  61. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/mock_pb2.py +0 -0
  62. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  63. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/server_async_insecure.py +0 -0
  64. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/server_async_secure.py +0 -0
  65. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/server_sync_insecure.py +0 -0
  66. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/base_server/server_sync_secure.py +0 -0
  67. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/modules/__init__.py +0 -0
  68. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/modules/cpu_intensive_module.py +0 -0
  69. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/modules/dynamic_setup_module.py +0 -0
  70. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/modules/minimal_llm_module.py +0 -0
  71. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/modules/text_transform_module.py +0 -0
  72. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/services/filesystem_module.py +0 -0
  73. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/examples/services/storage_module.py +0 -0
  74. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/setup.cfg +0 -0
  75. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/__init__.py +0 -0
  76. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/__init__.py +0 -0
  77. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/common/__init__.py +0 -0
  78. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/common/factories.py +0 -0
  79. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/__init__.py +0 -0
  80. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  81. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
  82. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/__init__.py +0 -0
  83. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  84. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  85. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/__init__.py +0 -0
  86. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  87. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  88. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
  89. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  90. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/logger.py +0 -0
  91. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/__init__.py +0 -0
  92. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/base_mixin.py +0 -0
  93. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/callback_mixin.py +0 -0
  94. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
  95. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/cost_mixin.py +0 -0
  96. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  97. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  98. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/logger_mixin.py +0 -0
  99. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/mixins/storage_mixin.py +0 -0
  100. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/__init__.py +0 -0
  101. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/__init__.py +0 -0
  102. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/core/job_manager_models.py +0 -0
  103. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  104. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/grpc_servers/types.py +0 -0
  105. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/base_types.py +0 -0
  106. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/module.py +0 -0
  107. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/module_types.py +0 -0
  108. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/module/utility.py +0 -0
  109. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/__init__.py +0 -0
  110. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/models/services/storage.py +0 -0
  111. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/__init__.py +0 -0
  112. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/archetype_module.py +0 -0
  113. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/tool_module.py +0 -0
  114. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/trigger_handler.py +0 -0
  115. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/__init__.py +0 -0
  116. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  117. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  118. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  119. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/py.typed +0 -0
  120. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/__init__.py +0 -0
  121. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/__init__.py +0 -0
  122. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/agent_strategy.py +0 -0
  123. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/agent/default_agent.py +0 -0
  124. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/base_strategy.py +0 -0
  125. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/communication/__init__.py +0 -0
  126. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/cost/__init__.py +0 -0
  127. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/__init__.py +0 -0
  128. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  129. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  130. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/__init__.py +0 -0
  131. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/default_identity.py +0 -0
  132. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  133. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/registry/exceptions.py +0 -0
  134. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/services_models.py +0 -0
  135. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/__init__.py +0 -0
  136. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/default_setup.py +0 -0
  137. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  138. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  139. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/__init__.py +0 -0
  140. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
  141. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
  142. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/__init__.py +0 -0
  143. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/default_storage.py +0 -0
  144. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  145. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  146. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/__init__.py +0 -0
  147. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  148. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  149. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  150. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/arg_parser.py +0 -0
  151. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/development_mode_action.py +0 -0
  152. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  153. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin/utils/package_discover.py +0 -0
  154. {digitalkin-0.3.2a2 → digitalkin-0.3.2.dev3}/src/digitalkin.egg-info/dependency_links.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.3.2a2
3
+ Version: 0.3.2.dev3
4
4
  Summary: SDK to build kin used in DigitalKin
5
5
  Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
6
6
  License: Attribution-NonCommercial-ShareAlike 4.0 International
@@ -434,32 +434,32 @@ License: Attribution-NonCommercial-ShareAlike 4.0 International
434
434
  Creative Commons may be contacted at creativecommons.org.
435
435
  https://creativecommons.org/licenses/by-nc-sa/4.0/
436
436
 
437
- Project-URL: Documentation, https://github.com/DigitalKin-ai/digitalkin
438
437
  Project-URL: Homepage, https://github.com/DigitalKin-ai/digitalkin
438
+ Project-URL: Documentation, https://github.com/DigitalKin-ai/digitalkin
439
439
  Project-URL: Issues, https://github.com/DigitalKin-ai/digitalkin/issues
440
- Keywords: agent,digitalkin,gprc,kin,sdk
440
+ Keywords: digitalkin,kin,agent,gprc,sdk
441
441
  Classifier: Development Status :: 3 - Alpha
442
442
  Classifier: Intended Audience :: Developers
443
- Classifier: License :: Other/Proprietary License
444
443
  Classifier: Operating System :: OS Independent
445
- Classifier: Programming Language :: Python :: 3 :: Only
444
+ Classifier: Topic :: Software Development :: Libraries
445
+ Classifier: Programming Language :: Python
446
446
  Classifier: Programming Language :: Python :: 3.10
447
447
  Classifier: Programming Language :: Python :: 3.11
448
448
  Classifier: Programming Language :: Python :: 3.12
449
449
  Classifier: Programming Language :: Python :: 3.13
450
- Classifier: Programming Language :: Python
451
- Classifier: Topic :: Software Development :: Libraries
450
+ Classifier: Programming Language :: Python :: 3 :: Only
451
+ Classifier: License :: Other/Proprietary License
452
452
  Requires-Python: >=3.10
453
453
  Description-Content-Type: text/markdown
454
454
  License-File: LICENSE
455
- Requires-Dist: agentic-mesh-protocol==0.2.1.dev1
455
+ Requires-Dist: agentic-mesh-protocol==0.2.1.dev0
456
456
  Requires-Dist: grpcio-health-checking>=1.76.0
457
457
  Requires-Dist: grpcio-reflection>=1.76.0
458
458
  Requires-Dist: grpcio-status>=1.76.0
459
459
  Requires-Dist: pydantic>=2.12.5
460
460
  Requires-Dist: surrealdb>=1.0.7
461
461
  Provides-Extra: taskiq
462
- Requires-Dist: rstream>=0.40.1; extra == "taskiq"
462
+ Requires-Dist: rstream>=0.40.0; extra == "taskiq"
463
463
  Requires-Dist: taskiq-aio-pika>=0.5.0; extra == "taskiq"
464
464
  Requires-Dist: taskiq-redis>=1.2.0; extra == "taskiq"
465
465
  Requires-Dist: taskiq[reload]>=0.12.1; extra == "taskiq"
@@ -1,34 +1,34 @@
1
1
  [build-system]
2
- build-backend = "setuptools.build_meta"
3
2
  requires = [ "setuptools >= 75.8.2", "wheel" ]
3
+ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
 
7
- description = "SDK to build kin used in DigitalKin"
8
- license = { file = "LICENSE" }
9
7
  name = "digitalkin"
8
+ description = "SDK to build kin used in DigitalKin"
10
9
  readme = "README.md"
11
10
  requires-python = ">=3.10"
11
+ license = { file = "LICENSE" }
12
12
 
13
- keywords = [ "agent", "digitalkin", "gprc", "kin", "sdk" ]
13
+ keywords = [ "digitalkin", "kin", "agent", "gprc", "sdk" ]
14
14
 
15
+ version = "0.3.2.dev3"
15
16
  classifiers = [
16
17
  "Development Status :: 3 - Alpha",
17
18
  "Intended Audience :: Developers",
18
- "License :: Other/Proprietary License",
19
19
  "Operating System :: OS Independent",
20
- "Programming Language :: Python :: 3 :: Only",
20
+ "Topic :: Software Development :: Libraries",
21
+ "Programming Language :: Python",
21
22
  "Programming Language :: Python :: 3.10",
22
23
  "Programming Language :: Python :: 3.11",
23
24
  "Programming Language :: Python :: 3.12",
24
25
  "Programming Language :: Python :: 3.13",
25
- "Programming Language :: Python",
26
- "Topic :: Software Development :: Libraries",
26
+ "Programming Language :: Python :: 3 :: Only",
27
+ "License :: Other/Proprietary License",
27
28
  ]
28
- version = "0.3.2.a2"
29
29
 
30
30
  dependencies = [
31
- "agentic-mesh-protocol==0.2.1.dev1",
31
+ "agentic-mesh-protocol==0.2.1.dev0",
32
32
  "grpcio-health-checking>=1.76.0",
33
33
  "grpcio-reflection>=1.76.0",
34
34
  "grpcio-status>=1.76.0",
@@ -38,81 +38,81 @@
38
38
 
39
39
  [project.optional-dependencies]
40
40
  taskiq = [
41
- "rstream>=0.40.1",
41
+ "rstream>=0.40.0",
42
42
  "taskiq-aio-pika>=0.5.0",
43
43
  "taskiq-redis>=1.2.0",
44
44
  "taskiq[reload]>=0.12.1",
45
45
  ]
46
46
 
47
47
  [project.urls]
48
- Documentation = "https://github.com/DigitalKin-ai/digitalkin"
49
48
  Homepage = "https://github.com/DigitalKin-ai/digitalkin"
49
+ Documentation = "https://github.com/DigitalKin-ai/digitalkin"
50
50
  Issues = "https://github.com/DigitalKin-ai/digitalkin/issues"
51
51
 
52
52
  [[project.authors]]
53
- email = "contact@digitalkin.ai"
54
53
  name = "DigitalKin.ai"
54
+ email = "contact@digitalkin.ai"
55
55
 
56
56
  [dependency-groups]
57
+ dev = [
58
+ "typos>=1.40.0",
59
+ "ruff>=0.14.9",
60
+ "mypy>=1.19.1",
61
+ "pyright>=1.1.407",
62
+ "pre-commit>=4.5.0",
63
+ "bump-my-version>=1.2.5",
64
+ "build>=1.3.0",
65
+ "twine>=6.2.0",
66
+ "cryptography>=46.0.3",
67
+ ]
57
68
  tests = [
58
69
  "freezegun>=1.5.5",
59
- "grpcio-testing>=1.76.0",
60
70
  "hdrhistogram>=0.10.3",
71
+ "grpcio-testing>=1.76.0",
61
72
  "psutil>=7.1.3",
73
+ "pytest>=9.0.2",
62
74
  "pytest-asyncio>=1.3.0",
63
75
  "pytest-cov>=7.0.0",
64
- "pytest-html==4.2.0",
76
+ "pytest-html==4.1.1",
65
77
  "pytest-json-report==1.5.0",
66
78
  "pytest-timeout>=2.4.0",
67
- "pytest>=9.0.2",
68
- ]
69
- dev = [
70
- "build>=1.3.0",
71
- "bump-my-version>=1.2.5",
72
- "cryptography>=46.0.4",
73
- "mypy>=1.19.1",
74
- "pre-commit>=4.5.1",
75
- "pyright>=1.1.407",
76
- "ruff>=0.14.14",
77
- "twine>=6.2.0",
78
- "typos>=1.42.3",
79
79
  ]
80
80
  docs = [
81
- "griffe-inherited-docstrings>=1.1.2",
81
+ "mike>=2.1.3",
82
82
  "markdown-callouts>=0.4.0",
83
83
  "markdown-exec>=1.12.1",
84
- "mike>=2.1.3",
84
+ "mkdocs>=1.6.1",
85
+ "mkdocs-coverage>=2.0.0",
86
+ "mkdocs-llmstxt>=0.5.0",
87
+ "mkdocs-redirects>=1.2.2",
88
+ "mkdocstrings>=1.0.0",
89
+ "griffe-inherited-docstrings>=1.1.2",
85
90
  "mkdocs-autorefs>=1.4.3",
86
91
  "mkdocs-awesome-pages-plugin>=2.10.1",
87
- "mkdocs-coverage>=2.0.0",
88
92
  "mkdocs-git-committers-plugin-2>=2.5.0",
89
- "mkdocs-git-revision-date-localized-plugin>=1.5.1",
93
+ "mkdocs-git-revision-date-localized-plugin>=1.5.0",
90
94
  "mkdocs-glightbox>=0.5.2",
91
- "mkdocs-include-markdown-plugin>=7.2.1",
95
+ "mkdocs-include-markdown-plugin>=7.2.0",
92
96
  "mkdocs-literate-nav>=0.6.2",
93
- "mkdocs-llmstxt>=0.5.0",
94
97
  "mkdocs-material[imaging]>=9.7.0",
95
98
  "mkdocs-minify-plugin>=0.8.0",
96
- "mkdocs-open-in-new-tab>=1.0.8",
97
- "mkdocs-redirects>=1.2.2",
98
99
  "mkdocs-section-index>=0.3.10",
99
- "mkdocs>=1.6.1",
100
100
  "mkdocstrings-python>=2.0.1",
101
- "mkdocstrings>=1.0.2",
101
+ "mkdocs-open-in-new-tab>=1.0.8",
102
102
  "tomli>=2.3.0",
103
103
  ]
104
104
  [tool.setuptools]
105
105
  package-dir = { "" = "src" }
106
106
 
107
107
  [tool.setuptools.packages.find]
108
- where = [ "examples", "src" ]
109
- [tool.ruff]
108
+ where = [ "src", "examples" ]
110
109
 
111
- indent-width = 4
112
- line-length = 120
113
- show-fixes = true
110
+ [tool.ruff]
114
111
  src = [ "src" ]
115
112
  target-version = "py310"
113
+ line-length = 120
114
+ indent-width = 4
115
+ show-fixes = true
116
116
  unsafe-fixes = true
117
117
  # Enable preview features.
118
118
  exclude = [
@@ -135,59 +135,59 @@
135
135
  "buck-out",
136
136
  "build",
137
137
  "dist",
138
- "docs/*",
139
- "examples/*",
138
+ "node_modules",
139
+ "venv",
140
140
  "factory.py",
141
141
  "generate_certificates.py",
142
- "node_modules",
142
+ "examples/*",
143
143
  "tests/*",
144
- "venv",
144
+ "docs/*",
145
145
  ]
146
146
  preview = true
147
147
 
148
148
  [tool.ruff.lint]
149
149
  select = [
150
- "A", # flake8-builtins
151
150
  "ANN", # flake8-annotations
152
- "ARG", # flake8-unused-arguments
153
151
  "ASYNC", # flake8-async
154
- "C4", # flake8-comprehensions
155
- "C90", # mccabe (complex-structure)
152
+ "S", # flake8-bandit
153
+ "FBT", # flake8-boolean-trap
154
+ "A", # flake8-builtins
156
155
  "COM", # flake8-commas
157
- "D", # pydocstyle
158
- "DOC", # pydoclint
156
+ "C4", # flake8-comprehensions
159
157
  "DTZ", # flake8-datetimez
160
- "E", # pycodestyle-errors
161
158
  "EM", # flake8-errmsg
162
- "ERA", # eradicate
163
- "F", # pyflakes
164
- "FBT", # flake8-boolean-trap
165
- "FLY", # flynt
166
- "FURB", # Refurb
167
- "G", # flake8-logging-format
168
- "I", # isort
169
- "ICN", # flake8-import-conventions
170
159
  "ISC", # flake8-implicit-str-concat
160
+ "ICN", # flake8-import-conventions
161
+ "G", # flake8-logging-format
171
162
  "LOG", # flake8-logging
172
- "N", # pep8-naming
173
- "PERF", # Perflint
174
163
  "PIE", # flake8-pie
175
- "PL", # Pylint
176
- "PL", # Pylint
177
- "PT", # flake8-pytest-style
164
+ "T20", # flake8-print
178
165
  "PYI", # flake8-pyi
166
+ "PT", # flake8-pytest-style
179
167
  "Q", # flake8-quotes
180
- "RET", # flake8-return
181
168
  "RSE", # flake8-raise
182
- "RUF", # Ruff-specific rules
183
- "S", # flake8-bandit
184
- "SIM", # flake8-simplify
169
+ "RET", # flake8-return
185
170
  "SLF", # flake8-self
186
- "T20", # flake8-print
171
+ "SIM", # flake8-simplify
187
172
  "TC", # flake8-type-checking
173
+ "ARG", # flake8-unused-arguments
174
+ "FLY", # flynt
175
+ "C90", # mccabe (complex-structure)
176
+ "PL", # Pylint
188
177
  "TRY", # tryceratops
189
- "UP", # pyupgrade
178
+ "PERF", # Perflint
179
+ "E", # pycodestyle-errors
190
180
  "W", # pycodestyle-warnings
181
+ "F", # pyflakes
182
+ "I", # isort
183
+ "D", # pydocstyle
184
+ "UP", # pyupgrade
185
+ "N", # pep8-naming
186
+ "ERA", # eradicate
187
+ "RUF", # Ruff-specific rules
188
+ "DOC", # pydoclint
189
+ "FURB", # Refurb
190
+ "PL", # Pylint
191
191
  ]
192
192
 
193
193
  ignore = [
@@ -203,66 +203,66 @@
203
203
 
204
204
  [tool.ruff.lint.per-file-ignores]
205
205
  "tests/**/*.py" = [
206
+ "S101",
207
+ "SLF001",
208
+ "PLC2701",
209
+ "PLR6301",
210
+ "TRY002",
211
+ "FBT001",
212
+ "FBT002",
206
213
  "ANN001",
207
- "ANN002",
208
214
  "ANN003",
209
- "ANN201",
210
- "ANN401",
211
- "ARG001",
215
+ "ANN002",
212
216
  "ARG002",
213
- "C901",
214
- "D100",
215
- "D101",
216
- "D102",
217
+ "PLR0914",
218
+ "PLR2004",
219
+ "PLR0915",
220
+ "PLR1702",
221
+ "D417",
222
+ "ARG001",
217
223
  "D103",
224
+ "D102",
225
+ "D101",
218
226
  "D107",
219
- "D417",
227
+ "N802",
220
228
  "DOC201",
221
229
  "DOC501",
222
- "E501",
223
- "ERA001",
224
- "FBT001",
225
- "FBT002",
226
- "G004",
227
- "N802",
228
230
  "PERF203",
229
- "PLC2701",
231
+ "C901",
230
232
  "PLR0911",
233
+ "G004",
234
+ "ERA001",
235
+ "E501",
236
+ "ANN401",
231
237
  "PLR0912",
232
- "PLR0914",
233
- "PLR0915",
234
- "PLR1702",
235
- "PLR2004",
236
- "PLR6301",
237
- "S101",
238
- "SLF001",
239
- "TRY002",
238
+ "ANN201",
239
+ "D100",
240
240
  ]
241
241
 
242
242
  [tool.ruff.lint.pylint]
243
243
  max-args = 10
244
244
 
245
245
  [tool.ruff.format]
246
- docstring-code-format = true
246
+ quote-style = "double"
247
247
  indent-style = "space"
248
248
  line-ending = "auto"
249
- quote-style = "double"
249
+ docstring-code-format = true
250
250
  skip-magic-trailing-comma = false
251
251
 
252
252
  [tool.pyright]
253
- exclude = [ "**/.venv", "**/__pycache__" ]
254
253
  include = [ "src" ]
254
+ exclude = [ "**/.venv", "**/__pycache__" ]
255
255
 
256
256
  [tool.mypy]
257
+ exclude = [ "tests", "examples" ]
257
258
 
258
- exclude = [ "examples", "tests" ]
259
259
  [tool.pytest.ini_options]
260
-
261
- asyncio_mode = "auto"
262
- python_files = "test_*.py"
263
260
  testpaths = [ "tests" ]
264
- log_cli = false
265
- log_level = "ERROR"
261
+ python_files = "test_*.py"
262
+ asyncio_mode = "auto"
263
+
264
+ log_cli = false
265
+ log_level = "ERROR"
266
266
 
267
267
  # Default timeout for tests (in seconds)
268
268
  timeout = 10
@@ -270,10 +270,10 @@
270
270
 
271
271
  # Custom markers
272
272
  markers = [
273
- "edge_case: marks tests for boundary conditions and edge cases",
274
- "grpc: marks tests for gRPC service functionality",
275
273
  "integration: marks tests that require real SurrealDB connection (deselect with '-m \"not integration\"')",
276
- "regression: marks tests for previously fixed bugs",
274
+ "grpc: marks tests for gRPC service functionality",
277
275
  "smoke: marks critical path tests that should always pass",
276
+ "edge_case: marks tests for boundary conditions and edge cases",
278
277
  "validation: marks tests for input validation and schema checking",
278
+ "regression: marks tests for previously fixed bugs",
279
279
  ]
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "0.3.2.a2"
8
+ __version__ = "0.3.2.dev3"
@@ -5,7 +5,7 @@ import datetime
5
5
  import uuid
6
6
  from collections.abc import AsyncGenerator, AsyncIterator
7
7
  from contextlib import asynccontextmanager
8
- from typing import TYPE_CHECKING, Any
8
+ from typing import Any
9
9
 
10
10
  import grpc
11
11
 
@@ -13,9 +13,6 @@ from digitalkin.core.common import ConnectionFactory, ModuleFactory
13
13
  from digitalkin.core.job_manager.base_job_manager import BaseJobManager
14
14
  from digitalkin.core.task_manager.local_task_manager import LocalTaskManager
15
15
  from digitalkin.core.task_manager.task_session import TaskSession
16
-
17
- if TYPE_CHECKING:
18
- from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
19
16
  from digitalkin.logger import logger
20
17
  from digitalkin.models.core.task_monitor import TaskStatus
21
18
  from digitalkin.models.module.base_types import InputModelT, OutputModelT, SetupModelT
@@ -32,6 +29,10 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
32
29
  to handle their output data.
33
30
  """
34
31
 
32
+ async def start(self) -> None:
33
+ """Start manager."""
34
+ self.channel = await ConnectionFactory.create_surreal_connection("task_manager", datetime.timedelta(seconds=5))
35
+
35
36
  def __init__(
36
37
  self,
37
38
  module_class: type[BaseModule],
@@ -54,11 +55,6 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
54
55
  super().__init__(module_class, services_mode, task_manager)
55
56
 
56
57
  self._lock = asyncio.Lock()
57
- self.channel: SurrealDBConnection | None = None
58
-
59
- async def start(self) -> None:
60
- """Start manager."""
61
- self.channel = await ConnectionFactory.create_surreal_connection("task_manager", datetime.timedelta(seconds=5))
62
58
 
63
59
  async def generate_config_setup_module_response(self, job_id: str) -> SetupModelT | ModuleCodeModel:
64
60
  """Generate a stream consumer for a module's output data.
@@ -117,14 +113,11 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
117
113
  str: The unique identifier (job ID) of the created job.
118
114
 
119
115
  Raises:
120
- RuntimeError: If start() was not called before creating jobs.
121
116
  Exception: If the module fails to start.
122
117
  """
123
118
  job_id = str(uuid.uuid4())
119
+ # TODO: Ensure the job_id is unique.
124
120
  module = ModuleFactory.create_module_instance(self.module_class, job_id, mission_id, setup_id, setup_version_id)
125
- if self.channel is None:
126
- msg = "JobManager.start() must be called before creating jobs"
127
- raise RuntimeError(msg)
128
121
  self.tasks_sessions[job_id] = TaskSession(job_id, mission_id, self.channel, module)
129
122
 
130
123
  try:
@@ -144,33 +137,13 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
144
137
  async def add_to_queue(self, job_id: str, output_data: OutputModelT | ModuleCodeModel) -> None:
145
138
  """Add output data to the queue for a specific job.
146
139
 
147
- Uses timeout-based backpressure: if the queue is full after 5s,
148
- drops the oldest message to make room for the new one.
149
- Rejects writes after stream is closed to prevent message loss.
140
+ This method is used as a callback to handle output data generated by a module job.
150
141
 
151
142
  Args:
152
143
  job_id: The unique identifier of the job.
153
144
  output_data: The output data produced by the job.
154
145
  """
155
- session = self.tasks_sessions.get(job_id)
156
- if session is None:
157
- logger.warning("Queue write rejected - session not found", extra={"job_id": job_id})
158
- return
159
-
160
- if session.stream_closed:
161
- logger.debug("Queue write rejected - stream closed", extra={"job_id": job_id})
162
- return
163
-
164
- try:
165
- await asyncio.wait_for(session.queue.put(output_data.model_dump()), timeout=5.0)
166
- except asyncio.TimeoutError:
167
- logger.warning("Queue full, dropping oldest message", extra={"job_id": job_id})
168
- try:
169
- session.queue.get_nowait()
170
- session.queue.task_done()
171
- except asyncio.QueueEmpty:
172
- pass
173
- session.queue.put_nowait(output_data.model_dump())
146
+ await self.tasks_sessions[job_id].queue.put(output_data.model_dump())
174
147
 
175
148
  @asynccontextmanager # type: ignore
176
149
  async def generate_stream_consumer(self, job_id: str) -> AsyncIterator[AsyncGenerator[dict[str, Any], None]]: # type: ignore
@@ -207,39 +180,42 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
207
180
  logger.debug("Session: %s with Module %s", job_id, session.module)
208
181
 
209
182
  async def _stream() -> AsyncGenerator[dict[str, Any], Any]:
210
- """Stream output data from the module with bounded blocking.
183
+ """Stream output data from the module with simple blocking pattern.
211
184
 
212
- Uses a 1-second timeout on queue.get() to periodically re-check
213
- termination flags, preventing indefinite hangs when the task crashes
214
- without producing output.
185
+ This implementation uses a simple one-item-at-a-time pattern optimized
186
+ for local execution where we have direct access to session status:
187
+ 1. Block waiting for each item
188
+ 2. Check termination conditions after each item
189
+ 3. Clean shutdown when task completes
190
+
191
+ This pattern provides:
192
+ - Immediate termination when task completes
193
+ - Direct session status monitoring
194
+ - Simple, predictable behavior for local tasks
215
195
 
216
196
  Yields:
217
197
  dict: Output data generated by the module.
218
198
  """
219
199
  while True:
220
- if session.stream_closed or session.is_cancelled.is_set():
221
- logger.debug("Stream ending for job %s (pre-check)", job_id)
222
- break
223
-
224
- try:
225
- msg = await asyncio.wait_for(session.queue.get(), timeout=1.0)
226
- except asyncio.TimeoutError:
227
- continue
228
-
200
+ # Block for next item - if queue is empty but producer not finished yet
201
+ msg = await session.queue.get()
229
202
  try:
230
203
  yield msg
231
204
  finally:
205
+ # Always mark task as done, even if consumer raises exception
232
206
  session.queue.task_done()
233
207
 
208
+ # Check termination conditions after each message
209
+ # This allows immediate shutdown when the task completes
234
210
  if (
235
- session.stream_closed
236
- or session.is_cancelled.is_set()
211
+ session.is_cancelled.is_set()
237
212
  or (session.status is TaskStatus.COMPLETED and session.queue.empty())
238
213
  or session.status is TaskStatus.FAILED
239
214
  ):
240
215
  logger.debug(
241
- "Stream ending for job %s: status=%s, queue_empty=%s",
216
+ "Stream ending for job %s: cancelled=%s, status=%s, queue_empty=%s",
242
217
  job_id,
218
+ session.is_cancelled.is_set(),
243
219
  session.status,
244
220
  session.queue.empty(),
245
221
  )
@@ -286,18 +262,6 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
286
262
  logger.info("Managed task started: '%s'", job_id, extra={"task_id": job_id})
287
263
  return job_id
288
264
 
289
- async def clean_session(self, task_id: str, mission_id: str) -> bool:
290
- """Clean a task's session.
291
-
292
- Args:
293
- task_id: Unique identifier for the task.
294
- mission_id: Mission identifier.
295
-
296
- Returns:
297
- bool: True if the task was successfully cleaned, False otherwise.
298
- """
299
- return await self._task_manager.clean_session(task_id, mission_id)
300
-
301
265
  async def stop_module(self, job_id: str) -> bool:
302
266
  """Stop a running module job.
303
267
 
@@ -323,7 +287,7 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
323
287
  await self.cancel_task(job_id, session.mission_id)
324
288
  logger.debug(
325
289
  "Module stopped successfully",
326
- extra={"job_id": job_id, "mission_id": session.mission_id},
290
+ extra={"job_id": job_id, "mission_id": session.mission_id, "module_name": session.module.name},
327
291
  )
328
292
  except Exception:
329
293
  logger.exception("Error stopping module", extra={"job_id": job_id})
@@ -373,7 +337,7 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
373
337
  await asyncio.gather(*stop_tasks, return_exceptions=True)
374
338
 
375
339
  # Close SurrealDB connection after stopping all modules
376
- if self.channel is not None:
340
+ if hasattr(self, "channel"):
377
341
  try:
378
342
  await self.channel.close()
379
343
  logger.info("SingleJobManager: SurrealDB connection closed")
@@ -22,7 +22,6 @@ from digitalkin.core.common import ConnectionFactory, QueueFactory
22
22
  from digitalkin.core.job_manager.base_job_manager import BaseJobManager
23
23
  from digitalkin.core.job_manager.taskiq_broker import STREAM, STREAM_RETENTION, TASKIQ_BROKER, cleanup_global_resources
24
24
  from digitalkin.core.task_manager.remote_task_manager import RemoteTaskManager
25
- from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
26
25
  from digitalkin.logger import logger
27
26
  from digitalkin.models.core.task_monitor import TaskStatus
28
27
  from digitalkin.models.module.module_types import InputModelT, OutputModelT, SetupModelT
@@ -37,7 +36,6 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
37
36
  """Taskiq job manager for running modules in Taskiq tasks."""
38
37
 
39
38
  services_mode: ServicesMode
40
- channel: SurrealDBConnection | None
41
39
 
42
40
  @staticmethod
43
41
  def _define_consumer() -> Consumer:
@@ -115,7 +113,7 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
115
113
  async def _stop(self) -> None:
116
114
  """Stop the TaskiqJobManager and clean up all resources."""
117
115
  # Close SurrealDB connection
118
- if self.channel is not None:
116
+ if hasattr(self, "channel"):
119
117
  try:
120
118
  await self.channel.close()
121
119
  logger.info("TaskiqJobManager: SurrealDB connection closed")
@@ -130,9 +128,8 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
130
128
  await self.stream_consumer_task
131
129
 
132
130
  # Clean up job queues
133
- queue_count = len(self.job_queues)
134
131
  self.job_queues.clear()
135
- logger.info("TaskiqJobManager: Cleared %d job queues", queue_count)
132
+ logger.info("TaskiqJobManager: Cleared %d job queues", len(self.job_queues))
136
133
 
137
134
  # Call global cleanup for producer and broker
138
135
  await cleanup_global_resources()
@@ -164,7 +161,6 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
164
161
  self.job_queues: dict[str, asyncio.Queue] = {}
165
162
  self.max_queue_size = 1000
166
163
  self.stream_timeout = stream_timeout
167
- self.channel = None
168
164
 
169
165
  async def generate_config_setup_module_response(self, job_id: str) -> SetupModelT:
170
166
  """Generate a stream consumer for a module's output data.
@@ -433,7 +429,7 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
433
429
  return TaskStatus.FAILED
434
430
 
435
431
  # Safety check: if channel not initialized (start() wasn't called), return FAILED
436
- if self.channel is None:
432
+ if not hasattr(self, "channel") or self.channel is None:
437
433
  logger.warning("Job %s status check failed - channel not initialized", job_id)
438
434
  return TaskStatus.FAILED
439
435
 
@@ -525,7 +521,7 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
525
521
  for job_id in self.tasks_sessions:
526
522
  try:
527
523
  status = await self.get_module_status(job_id)
528
- task_record = await self.channel.select_by_task_id("tasks", job_id) # type: ignore
524
+ task_record = await self.channel.select_by_task_id("tasks", job_id)
529
525
 
530
526
  modules_info[job_id] = {
531
527
  "name": self.module_class.__name__,