digitalkin 0.3.5.dev12__tar.gz → 0.3.5.dev13__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.
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/PKG-INFO +3 -3
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/archetype_with_tools_module.py +3 -2
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/pyproject.toml +12 -12
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/__version__.py +1 -1
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/community/agno/agno_adapter.py +12 -25
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/job_manager/base_job_manager.py +6 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/job_manager/single_job_manager.py +1 -4
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/job_manager/taskiq_broker.py +211 -13
- digitalkin-0.3.5.dev13/src/digitalkin/core/job_manager/taskiq_job_manager.py +659 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/task_session.py +2 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/_base_server.py +56 -48
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/module_server.py +37 -12
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/module_servicer.py +42 -3
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +35 -10
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/__init__.py +0 -4
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/agui_mixin.py +3 -3
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/base_mixin.py +2 -2
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/callback_mixin.py +19 -5
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/chat_history_mixin.py +14 -8
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/grpc_servers/models.py +2 -138
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/__init__.py +0 -2
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/module_context.py +2 -18
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/setup_types.py +124 -13
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/tool_cache.py +51 -45
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/tool_reference.py +17 -9
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/__init__.py +1 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/server/__init__.py +1 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/server/channel.py +36 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/server/grpc.py +99 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/server/server.py +47 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/utils/__init__.py +1 -0
- digitalkin-0.3.5.dev13/src/digitalkin/models/settings/utils/channel.py +148 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/_base_module.py +38 -15
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +1 -1
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +2 -2
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +1 -1
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/registry_strategy.py +12 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/conditional_schema.py +2 -3
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin.egg-info/PKG-INFO +3 -3
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin.egg-info/SOURCES.txt +7 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin.egg-info/requires.txt +2 -2
- digitalkin-0.3.5.dev12/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -477
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/LICENSE +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/README.md +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/monitoring/tests/test_metrics.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/services/filesystem_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/services/storage_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/setup.cfg +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/community/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/community/agno/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/profiling/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/profiling/asyncio_monitor.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/profiling/task_profiler.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/logger.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/core/task_monitor.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/events/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/events/agent_events.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/ag_ui.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/base_types.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/module_types.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/request_metadata.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/select_schema.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/module/utility.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/modules/triggers/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/py.typed +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/agent/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/agent/agent_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/agent/default_agent.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/communication/grpc_communication.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/registry/registry_models.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/services_config.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/snapshot/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/task_manager/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/task_manager/grpc_task_manager.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/proto_utils.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/utils/schema_splitter.py +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digitalkin
|
|
3
|
-
Version: 0.3.5.
|
|
3
|
+
Version: 0.3.5.dev13
|
|
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
|
|
@@ -454,7 +454,7 @@ Description-Content-Type: text/markdown
|
|
|
454
454
|
License-File: LICENSE
|
|
455
455
|
Requires-Dist: ag-ui-protocol>=0.1.14
|
|
456
456
|
Requires-Dist: agentic-mesh-protocol==0.2.3
|
|
457
|
-
Requires-Dist: anyio==4.
|
|
457
|
+
Requires-Dist: anyio==4.13.0
|
|
458
458
|
Requires-Dist: grpcio-health-checking==1.78.0
|
|
459
459
|
Requires-Dist: grpcio-reflection==1.78.0
|
|
460
460
|
Requires-Dist: grpcio-status==1.78.0
|
|
@@ -463,7 +463,7 @@ Provides-Extra: profiling
|
|
|
463
463
|
Requires-Dist: asyncio-inspector==0.1.0; extra == "profiling"
|
|
464
464
|
Requires-Dist: pyinstrument==5.1.2; extra == "profiling"
|
|
465
465
|
Requires-Dist: viztracer==1.1.1; extra == "profiling"
|
|
466
|
-
Requires-Dist: yappi==1.7.
|
|
466
|
+
Requires-Dist: yappi==1.7.6; extra == "profiling"
|
|
467
467
|
Provides-Extra: taskiq
|
|
468
468
|
Requires-Dist: rstream==1.0.0; extra == "taskiq"
|
|
469
469
|
Requires-Dist: taskiq-aio-pika==0.6.0; extra == "taskiq"
|
{digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/examples/modules/archetype_with_tools_module.py
RENAMED
|
@@ -5,10 +5,11 @@ from typing import Any, ClassVar, Literal
|
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
|
-
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
8
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
9
9
|
from digitalkin.models.module.module_context import ModuleContext
|
|
10
10
|
from digitalkin.models.module.setup_types import SetupModel
|
|
11
11
|
from digitalkin.models.module.tool_reference import ToolReference
|
|
12
|
+
from digitalkin.models.settings.utils.channel import ControlFlow, SecurityMode
|
|
12
13
|
from digitalkin.modules._base_module import BaseModule # noqa: PLC2701
|
|
13
14
|
from digitalkin.services.services_models import ServicesStrategy
|
|
14
15
|
|
|
@@ -98,7 +99,7 @@ class ArchetypeSecret(BaseModel):
|
|
|
98
99
|
client_config = ClientConfig(
|
|
99
100
|
host="[::]",
|
|
100
101
|
port=50152,
|
|
101
|
-
mode=
|
|
102
|
+
mode=ControlFlow.ASYNC,
|
|
102
103
|
security=SecurityMode.INSECURE,
|
|
103
104
|
credentials=None,
|
|
104
105
|
)
|
|
@@ -29,20 +29,20 @@
|
|
|
29
29
|
dependencies = [
|
|
30
30
|
"ag-ui-protocol>=0.1.14",
|
|
31
31
|
"agentic-mesh-protocol==0.2.3",
|
|
32
|
-
"anyio==4.
|
|
32
|
+
"anyio==4.13.0",
|
|
33
33
|
"grpcio-health-checking==1.78.0",
|
|
34
34
|
"grpcio-reflection==1.78.0",
|
|
35
35
|
"grpcio-status==1.78.0",
|
|
36
36
|
"pydantic==2.12.5",
|
|
37
|
-
]
|
|
38
|
-
version = "0.3.5.
|
|
37
|
+
]
|
|
38
|
+
version = "0.3.5.dev13"
|
|
39
39
|
|
|
40
40
|
[project.optional-dependencies]
|
|
41
41
|
profiling = [
|
|
42
42
|
"asyncio-inspector==0.1.0",
|
|
43
43
|
"pyinstrument==5.1.2",
|
|
44
44
|
"viztracer==1.1.1",
|
|
45
|
-
"yappi==1.7.
|
|
45
|
+
"yappi==1.7.6",
|
|
46
46
|
]
|
|
47
47
|
taskiq = [
|
|
48
48
|
"rstream==1.0.0",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
|
|
62
62
|
[dependency-groups]
|
|
63
63
|
dev = [
|
|
64
|
-
"build==1.4.
|
|
64
|
+
"build==1.4.2",
|
|
65
65
|
"bump-my-version==1.2.7",
|
|
66
|
-
"cryptography==46.0.
|
|
66
|
+
"cryptography==46.0.6",
|
|
67
67
|
"mypy==1.19.1",
|
|
68
68
|
"pre-commit==4.5.1",
|
|
69
69
|
"pyright==1.1.408",
|
|
70
|
-
"ruff==0.15.
|
|
70
|
+
"ruff==0.15.8",
|
|
71
71
|
"twine==6.2.0",
|
|
72
72
|
"types-grpcio-health-checking==1.0.0.20250506",
|
|
73
73
|
"types-grpcio-reflection==1.0.0.20250506",
|
|
@@ -87,17 +87,17 @@
|
|
|
87
87
|
"mkdocs-git-revision-date-localized-plugin==1.5.1",
|
|
88
88
|
"mkdocs-glightbox==0.5.2",
|
|
89
89
|
"mkdocs-include-markdown-plugin==7.2.1",
|
|
90
|
-
"mkdocs-literate-nav==0.6.
|
|
90
|
+
"mkdocs-literate-nav==0.6.3",
|
|
91
91
|
"mkdocs-llmstxt==0.5.0",
|
|
92
|
-
"mkdocs-material[imaging]==9.7.
|
|
92
|
+
"mkdocs-material[imaging]==9.7.6",
|
|
93
93
|
"mkdocs-minify-plugin==0.8.0",
|
|
94
94
|
"mkdocs-open-in-new-tab==1.0.8",
|
|
95
95
|
"mkdocs-redirects==1.2.2",
|
|
96
|
-
"mkdocs-section-index==0.3.
|
|
96
|
+
"mkdocs-section-index==0.3.11",
|
|
97
97
|
"mkdocs==1.6.1",
|
|
98
98
|
"mkdocstrings-python==2.0.3",
|
|
99
99
|
"mkdocstrings==1.0.3",
|
|
100
|
-
"tomli==2.4.
|
|
100
|
+
"tomli==2.4.1",
|
|
101
101
|
]
|
|
102
102
|
tests = [
|
|
103
103
|
"freezegun==1.5.5",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"hdrhistogram==0.10.3",
|
|
106
106
|
"psutil==7.2.2",
|
|
107
107
|
"pytest-asyncio==1.3.0",
|
|
108
|
-
"pytest-cov==7.
|
|
108
|
+
"pytest-cov==7.1.0",
|
|
109
109
|
"pytest-html==4.2.0",
|
|
110
110
|
"pytest-json-report==1.5.0",
|
|
111
111
|
"pytest-timeout==2.4.0",
|
{digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/community/agno/agno_adapter.py
RENAMED
|
@@ -86,7 +86,7 @@ class AgnoStreamAdapter:
|
|
|
86
86
|
|
|
87
87
|
event_type = agno_event.event
|
|
88
88
|
|
|
89
|
-
logger.
|
|
89
|
+
logger.debug("Converting Agno event: %s", event_type)
|
|
90
90
|
|
|
91
91
|
timestamp = getattr(agno_event, "timestamp", None)
|
|
92
92
|
|
|
@@ -97,7 +97,7 @@ class AgnoStreamAdapter:
|
|
|
97
97
|
|
|
98
98
|
# Skip duplicate RunStarted for the same run_id
|
|
99
99
|
if run_id and run_id == self._active_run_id:
|
|
100
|
-
logger.
|
|
100
|
+
logger.debug("Skipping duplicate RunStarted for run_id=%s", run_id)
|
|
101
101
|
return []
|
|
102
102
|
|
|
103
103
|
self._active_run_id = run_id
|
|
@@ -119,7 +119,7 @@ class AgnoStreamAdapter:
|
|
|
119
119
|
|
|
120
120
|
# Skip if this run was already completed and not reopened
|
|
121
121
|
if run_id and run_id in self._completed_run_ids and run_id != self._active_run_id:
|
|
122
|
-
logger.
|
|
122
|
+
logger.debug("Skipping duplicate RunCompleted for run_id=%s", run_id)
|
|
123
123
|
return []
|
|
124
124
|
|
|
125
125
|
events: list[BaseAgentRunEvent] = []
|
|
@@ -169,10 +169,7 @@ class AgnoStreamAdapter:
|
|
|
169
169
|
|
|
170
170
|
self._current_reasoning_id = str(uuid.uuid4())
|
|
171
171
|
self._reasoning_active = True
|
|
172
|
-
logger.
|
|
173
|
-
"[DK STREAM-DEBUG => agno_adapter] Reasoning started (explicit), id=%s",
|
|
174
|
-
self._current_reasoning_id,
|
|
175
|
-
)
|
|
172
|
+
logger.debug("Reasoning started, id=%s", self._current_reasoning_id)
|
|
176
173
|
events.append(
|
|
177
174
|
ReasoningStartedEvent(
|
|
178
175
|
event=AgentRunEvent.REASONING_STARTED,
|
|
@@ -208,7 +205,7 @@ class AgnoStreamAdapter:
|
|
|
208
205
|
]
|
|
209
206
|
|
|
210
207
|
if event_type == RunEvent.reasoning_completed:
|
|
211
|
-
logger.
|
|
208
|
+
logger.debug("Reasoning completed")
|
|
212
209
|
return self._close_reasoning(timestamp)
|
|
213
210
|
|
|
214
211
|
# ── Tool Call Events ─────────────────────────────────────────────
|
|
@@ -218,7 +215,7 @@ class AgnoStreamAdapter:
|
|
|
218
215
|
|
|
219
216
|
# Close both reasoning and content before tool calls
|
|
220
217
|
if self._reasoning_active:
|
|
221
|
-
logger.
|
|
218
|
+
logger.debug("Reasoning auto-completed (tool call started)")
|
|
222
219
|
events.extend(self._close_reasoning(timestamp))
|
|
223
220
|
if self._content_active:
|
|
224
221
|
events.extend(self._close_content(timestamp))
|
|
@@ -275,10 +272,7 @@ class AgnoStreamAdapter:
|
|
|
275
272
|
|
|
276
273
|
# Skip if already closed by ToolCallCompleted (Agno emits both for the same tool_call_id)
|
|
277
274
|
if tool_call_id and tool_call_id in self._closed_tool_call_ids:
|
|
278
|
-
logger.
|
|
279
|
-
"[DK STREAM-DEBUG => agno_adapter] Skipping duplicate ToolCallError for already-closed tool %s",
|
|
280
|
-
tool_call_id,
|
|
281
|
-
)
|
|
275
|
+
logger.debug("Skipping duplicate ToolCallError for tool %s", tool_call_id)
|
|
282
276
|
return []
|
|
283
277
|
|
|
284
278
|
tool_info = None
|
|
@@ -315,10 +309,10 @@ class AgnoStreamAdapter:
|
|
|
315
309
|
"""
|
|
316
310
|
events: list[BaseAgentRunEvent] = []
|
|
317
311
|
if self._content_active:
|
|
318
|
-
logger.
|
|
312
|
+
logger.debug("Flushing active content sequence")
|
|
319
313
|
events.extend(self._close_content(None))
|
|
320
314
|
if self._reasoning_active:
|
|
321
|
-
logger.
|
|
315
|
+
logger.debug("Flushing active reasoning sequence")
|
|
322
316
|
events.extend(self._close_reasoning(None))
|
|
323
317
|
return events
|
|
324
318
|
|
|
@@ -394,7 +388,7 @@ class AgnoStreamAdapter:
|
|
|
394
388
|
|
|
395
389
|
# Edge case: neither reasoning_content nor content
|
|
396
390
|
if reasoning_content is None and content is None:
|
|
397
|
-
logger.debug("
|
|
391
|
+
logger.debug("run_content with no content, skipping")
|
|
398
392
|
|
|
399
393
|
return events
|
|
400
394
|
|
|
@@ -420,10 +414,7 @@ class AgnoStreamAdapter:
|
|
|
420
414
|
# Auto-open reasoning on first chunk
|
|
421
415
|
if not self._reasoning_active:
|
|
422
416
|
self._current_reasoning_id = str(uuid.uuid4())
|
|
423
|
-
logger.
|
|
424
|
-
"[DK STREAM-DEBUG => agno_adapter] Reasoning auto-started from run_content, id=%s",
|
|
425
|
-
self._current_reasoning_id,
|
|
426
|
-
)
|
|
417
|
+
logger.debug("Reasoning auto-started, id=%s", self._current_reasoning_id)
|
|
427
418
|
events.append(
|
|
428
419
|
ReasoningStartedEvent(
|
|
429
420
|
event=AgentRunEvent.REASONING_STARTED,
|
|
@@ -434,10 +425,6 @@ class AgnoStreamAdapter:
|
|
|
434
425
|
)
|
|
435
426
|
self._reasoning_active = True
|
|
436
427
|
|
|
437
|
-
logger.info(
|
|
438
|
-
"[DK STREAM-DEBUG => agno_adapter] Reasoning content delta (len=%d)",
|
|
439
|
-
len(reasoning_content),
|
|
440
|
-
)
|
|
441
428
|
events.append(
|
|
442
429
|
ReasoningContentDeltaEvent(
|
|
443
430
|
event=AgentRunEvent.REASONING_CONTENT_DELTA,
|
|
@@ -466,7 +453,7 @@ class AgnoStreamAdapter:
|
|
|
466
453
|
# Non-empty string → text data
|
|
467
454
|
# Close reasoning if transitioning from reasoning to content
|
|
468
455
|
if self._reasoning_active:
|
|
469
|
-
logger.
|
|
456
|
+
logger.debug("Reasoning auto-completed (text content arrived)")
|
|
470
457
|
events.extend(self._close_reasoning(timestamp))
|
|
471
458
|
|
|
472
459
|
# Auto-open text message on first chunk
|
|
@@ -130,6 +130,12 @@ class BaseJobManager(abc.ABC, Generic[InputModelT, OutputModelT, SetupModelT]):
|
|
|
130
130
|
required for the job manager to function.
|
|
131
131
|
"""
|
|
132
132
|
|
|
133
|
+
async def stop(self) -> None:
|
|
134
|
+
"""Stop the job manager and clean up resources.
|
|
135
|
+
|
|
136
|
+
Default no-op. Subclasses with external connections override.
|
|
137
|
+
"""
|
|
138
|
+
|
|
133
139
|
@staticmethod
|
|
134
140
|
async def job_specific_callback(
|
|
135
141
|
callback: Callable[[str, DataModel | ModuleCodeModel], Coroutine[Any, Any, None]],
|
|
@@ -285,10 +285,7 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
|
|
|
285
285
|
if session.cancelled:
|
|
286
286
|
break
|
|
287
287
|
|
|
288
|
-
|
|
289
|
-
yield _stream()
|
|
290
|
-
finally:
|
|
291
|
-
session.close_stream()
|
|
288
|
+
yield _stream()
|
|
292
289
|
|
|
293
290
|
async def create_module_instance_job(
|
|
294
291
|
self,
|
{digitalkin-0.3.5.dev12 → digitalkin-0.3.5.dev13}/src/digitalkin/core/job_manager/taskiq_broker.py
RENAMED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
"""Taskiq broker & RSTREAM producer for the job manager."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import json
|
|
5
4
|
import logging
|
|
6
5
|
import os
|
|
7
6
|
import pickle
|
|
7
|
+
import ssl
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
10
|
from rstream import Producer
|
|
11
11
|
from rstream.exceptions import PreconditionFailed
|
|
12
12
|
from taskiq import Context, TaskiqDepends, TaskiqMessage
|
|
13
13
|
from taskiq.abc.formatter import TaskiqFormatter
|
|
14
|
+
from taskiq.abc.middleware import TaskiqMiddleware
|
|
14
15
|
from taskiq.compat import model_validate
|
|
15
16
|
from taskiq.message import BrokerMessage
|
|
17
|
+
from taskiq.result import TaskiqResult
|
|
16
18
|
from taskiq_aio_pika import AioPikaBroker
|
|
17
19
|
|
|
18
20
|
from digitalkin.core.common import ModuleFactory
|
|
@@ -61,27 +63,79 @@ class PickleFormatter(TaskiqFormatter):
|
|
|
61
63
|
def loads(self, message: bytes) -> TaskiqMessage: # Required by TaskiqFormatter interface # noqa: PLR6301
|
|
62
64
|
"""Recreate Python object from bytes.
|
|
63
65
|
|
|
66
|
+
Non-pickle messages (e.g. raw JSON left in the queue by other producers)
|
|
67
|
+
are logged and converted to a no-op ``TaskiqMessage`` so that Taskiq
|
|
68
|
+
acknowledges (consumes) them instead of nack-ing and re-delivering in a loop.
|
|
69
|
+
|
|
64
70
|
Args:
|
|
65
71
|
message: Broker message from bytes.
|
|
66
72
|
|
|
67
73
|
Returns:
|
|
68
74
|
message with TaskIQ format
|
|
69
75
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
try:
|
|
77
|
+
json_str = pickle.loads( # noqa: S301
|
|
78
|
+
message
|
|
79
|
+
) # Pickle: required for Taskiq deserialization (internal broker messages only)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(
|
|
82
|
+
"Discarding non-pickle message (size=%d, preview=%r): %s",
|
|
83
|
+
len(message),
|
|
84
|
+
message[:80],
|
|
85
|
+
e,
|
|
86
|
+
)
|
|
87
|
+
# Return a no-op message that Taskiq will ack and discard
|
|
88
|
+
# (no task named "__discarded__" exists, so Taskiq logs a warning and moves on)
|
|
89
|
+
return TaskiqMessage(
|
|
90
|
+
task_id="__discarded__",
|
|
91
|
+
task_name="__discarded__",
|
|
92
|
+
labels={"_discarded": "true"},
|
|
93
|
+
args=[],
|
|
94
|
+
kwargs={},
|
|
95
|
+
)
|
|
73
96
|
return model_validate(TaskiqMessage, json_str)
|
|
74
97
|
|
|
75
98
|
|
|
99
|
+
def _rstream_ssl_context() -> ssl.SSLContext | None:
|
|
100
|
+
"""Create SSL context for RStream if TLS is enabled via RABBITMQ_RSTREAM_SSL=true.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
SSL context if TLS is enabled, None otherwise.
|
|
104
|
+
"""
|
|
105
|
+
if os.environ.get("RABBITMQ_RSTREAM_SSL", "").lower() not in {"true", "1", "yes"}:
|
|
106
|
+
return None
|
|
107
|
+
ctx = ssl.create_default_context()
|
|
108
|
+
# Allow self-signed certs in staging if RABBITMQ_RSTREAM_SSL_VERIFY=false
|
|
109
|
+
if os.environ.get("RABBITMQ_RSTREAM_SSL_VERIFY", "true").lower() in {"false", "0", "no"}:
|
|
110
|
+
ctx.check_hostname = False
|
|
111
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
112
|
+
return ctx
|
|
113
|
+
|
|
114
|
+
|
|
76
115
|
class TaskiqBrokerConfig:
|
|
77
116
|
"""Configuration and lifecycle management for Taskiq broker and RStream producer."""
|
|
78
117
|
|
|
79
118
|
STREAM = "taskiq_data"
|
|
80
119
|
STREAM_RETENTION = 200_000
|
|
81
120
|
|
|
121
|
+
@staticmethod
|
|
122
|
+
async def _on_producer_closed(reason: Any) -> None:
|
|
123
|
+
"""Log RStream producer connection closure for diagnostics.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
reason: Connection close reason from rstream.
|
|
127
|
+
"""
|
|
128
|
+
logger.error("RStream producer connection closed: %s", reason)
|
|
129
|
+
|
|
82
130
|
@staticmethod
|
|
83
131
|
def define_producer() -> Producer:
|
|
84
|
-
"""Create RStream producer
|
|
132
|
+
"""Create RStream producer with tuned settings for sustained throughput.
|
|
133
|
+
|
|
134
|
+
Tuning:
|
|
135
|
+
- ``default_batch_publishing_delay``: Flush batches every 100ms (default 3s)
|
|
136
|
+
for lower streaming latency during long-running tasks.
|
|
137
|
+
- ``default_context_switch_value``: Yield to the event loop every 100 messages
|
|
138
|
+
(default 1000) to keep concurrent coroutines responsive under heavy output.
|
|
85
139
|
|
|
86
140
|
Returns:
|
|
87
141
|
Producer connected to RabbitMQ.
|
|
@@ -91,12 +145,22 @@ class TaskiqBrokerConfig:
|
|
|
91
145
|
username = os.environ.get("RABBITMQ_RSTREAM_USERNAME", "guest")
|
|
92
146
|
password = os.environ.get("RABBITMQ_RSTREAM_PASSWORD", "guest")
|
|
93
147
|
|
|
94
|
-
logger.info("
|
|
95
|
-
return Producer(
|
|
148
|
+
logger.info("RStream producer connecting to %s:%s", host, port)
|
|
149
|
+
return Producer(
|
|
150
|
+
host=host,
|
|
151
|
+
port=int(port),
|
|
152
|
+
username=username,
|
|
153
|
+
password=password,
|
|
154
|
+
ssl_context=_rstream_ssl_context(),
|
|
155
|
+
default_batch_publishing_delay=float(os.environ.get("DIGITALKIN_RSTREAM_BATCH_DELAY", "0.1")),
|
|
156
|
+
default_context_switch_value=int(os.environ.get("DIGITALKIN_RSTREAM_CONTEXT_SWITCH", "100")),
|
|
157
|
+
connection_name="digitalkin_producer",
|
|
158
|
+
on_close_handler=TaskiqBrokerConfig._on_producer_closed,
|
|
159
|
+
)
|
|
96
160
|
|
|
97
161
|
@staticmethod
|
|
98
162
|
def define_broker() -> AioPikaBroker:
|
|
99
|
-
"""Create AioPikaBroker
|
|
163
|
+
"""Create AioPikaBroker with tuned QoS for worker prefetch control.
|
|
100
164
|
|
|
101
165
|
Returns:
|
|
102
166
|
Broker connected to RabbitMQ with custom formatter.
|
|
@@ -105,12 +169,19 @@ class TaskiqBrokerConfig:
|
|
|
105
169
|
port = os.environ.get("RABBITMQ_BROKER_PORT", "5672")
|
|
106
170
|
username = os.environ.get("RABBITMQ_BROKER_USERNAME", "guest")
|
|
107
171
|
password = os.environ.get("RABBITMQ_BROKER_PASSWORD", "guest")
|
|
172
|
+
scheme = os.environ.get("RABBITMQ_BROKER_SCHEME", "amqp")
|
|
108
173
|
|
|
109
174
|
broker = AioPikaBroker(
|
|
110
|
-
f"
|
|
175
|
+
f"{scheme}://{username}:{password}@{host}:{port}",
|
|
176
|
+
qos=int(os.environ.get("DIGITALKIN_TASKIQ_PREFETCH", "10")),
|
|
111
177
|
startup=[TaskiqBrokerConfig.init_rstream],
|
|
112
178
|
)
|
|
113
179
|
broker.formatter = PickleFormatter()
|
|
180
|
+
redis_url = os.environ.get("DIGITALKIN_TASKIQ_RESULT_BACKEND_URL")
|
|
181
|
+
if redis_url:
|
|
182
|
+
from taskiq_redis import RedisAsyncResultBackend
|
|
183
|
+
|
|
184
|
+
broker.with_result_backend(RedisAsyncResultBackend(redis_url))
|
|
114
185
|
return broker
|
|
115
186
|
|
|
116
187
|
@staticmethod
|
|
@@ -147,17 +218,78 @@ class TaskiqBrokerConfig:
|
|
|
147
218
|
async def send_message_to_stream(job_id: str, output_data: DataModel | ModuleCodeModel) -> None:
|
|
148
219
|
"""Add a message frame to the RStream.
|
|
149
220
|
|
|
221
|
+
Uses Pydantic's Rust-based model_dump_json() and direct string embedding
|
|
222
|
+
to avoid the overhead of model_dump() → dict → json.dumps() → encode().
|
|
223
|
+
|
|
150
224
|
Args:
|
|
151
225
|
job_id: ID of the job that sent the message.
|
|
152
226
|
output_data: Message body as a OutputModelT or error / stream_code.
|
|
153
227
|
"""
|
|
154
|
-
|
|
228
|
+
# job_id is always a UUID (hex + hyphens), safe to embed without escaping
|
|
229
|
+
output_json = output_data.model_dump_json()
|
|
230
|
+
body = f'{{"job_id":"{job_id}","output_data":{output_json}}}'.encode()
|
|
155
231
|
await RSTREAM_PRODUCER.send(stream=TaskiqBrokerConfig.STREAM, message=body)
|
|
156
232
|
|
|
157
233
|
|
|
234
|
+
class TaskiqLifecycleMiddleware(TaskiqMiddleware):
|
|
235
|
+
"""Lifecycle middleware for structured logging and safety-net EndOfStreamOutput."""
|
|
236
|
+
|
|
237
|
+
async def pre_execute(self, message: TaskiqMessage) -> TaskiqMessage: # noqa: PLR6301
|
|
238
|
+
"""Log task start.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
The unmodified message.
|
|
242
|
+
"""
|
|
243
|
+
logger.info("Taskiq task starting: %s (task_name=%s)", message.task_id, message.task_name)
|
|
244
|
+
return message
|
|
245
|
+
|
|
246
|
+
async def post_execute(self, message: TaskiqMessage, result: TaskiqResult) -> None: # noqa: PLR6301
|
|
247
|
+
"""Log task completion."""
|
|
248
|
+
log_fn = logger.info if not result.is_err else logger.error
|
|
249
|
+
log_fn(
|
|
250
|
+
"Taskiq task finished: %s (task_name=%s, is_err=%s, exec_time=%.3fs)",
|
|
251
|
+
message.task_id,
|
|
252
|
+
message.task_name,
|
|
253
|
+
result.is_err,
|
|
254
|
+
result.execution_time,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
async def on_error( # noqa: PLR6301
|
|
258
|
+
self,
|
|
259
|
+
message: TaskiqMessage,
|
|
260
|
+
result: TaskiqResult, # noqa: ARG002
|
|
261
|
+
exception: BaseException,
|
|
262
|
+
) -> None:
|
|
263
|
+
"""Safety net: send EndOfStreamOutput if worker task failed to."""
|
|
264
|
+
logger.error("Taskiq task error: %s (task_name=%s, error=%s)", message.task_id, message.task_name, exception)
|
|
265
|
+
try:
|
|
266
|
+
await TaskiqBrokerConfig.send_message_to_stream(
|
|
267
|
+
message.task_id,
|
|
268
|
+
ModuleCodeModel(code="WorkerCrash", short_description="Middleware safety net", message=str(exception)),
|
|
269
|
+
)
|
|
270
|
+
await TaskiqBrokerConfig.send_message_to_stream(
|
|
271
|
+
message.task_id,
|
|
272
|
+
DataModel(root=EndOfStreamOutput()),
|
|
273
|
+
)
|
|
274
|
+
except Exception:
|
|
275
|
+
logger.exception("Middleware safety net failed for %s", message.task_id)
|
|
276
|
+
|
|
277
|
+
|
|
158
278
|
# Module-level globals required by Taskiq framework (decorator needs broker at import time)
|
|
159
279
|
RSTREAM_PRODUCER = TaskiqBrokerConfig.define_producer()
|
|
160
280
|
TASKIQ_BROKER = TaskiqBrokerConfig.define_broker()
|
|
281
|
+
TASKIQ_BROKER.add_middlewares(TaskiqLifecycleMiddleware())
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@TASKIQ_BROKER.task(task_name="__discarded__")
|
|
285
|
+
async def _discarded_message() -> None: # noqa: RUF029
|
|
286
|
+
"""No-op sink for poison messages consumed by PickleFormatter.
|
|
287
|
+
|
|
288
|
+
Taskiq's receiver early-returns without acking when a task name is unknown,
|
|
289
|
+
so we register this dummy task to ensure the message is executed (no-op),
|
|
290
|
+
acked, and removed from the queue.
|
|
291
|
+
"""
|
|
292
|
+
logger.debug("Poison message acknowledged and discarded")
|
|
161
293
|
|
|
162
294
|
|
|
163
295
|
@TASKIQ_BROKER.task
|
|
@@ -170,6 +302,7 @@ async def run_start_module(
|
|
|
170
302
|
input_data: dict,
|
|
171
303
|
setup_data: dict,
|
|
172
304
|
request_metadata: dict[str, str] | None = None,
|
|
305
|
+
registry_config: dict[str, Any] | None = None,
|
|
173
306
|
context: Context = TaskiqDepends(),
|
|
174
307
|
) -> None:
|
|
175
308
|
"""TaskIQ task allowing a module to compute in the background asynchronously.
|
|
@@ -183,9 +316,17 @@ async def run_start_module(
|
|
|
183
316
|
input_data: dict,
|
|
184
317
|
setup_data: dict,
|
|
185
318
|
request_metadata: gRPC request metadata (headers) to forward to the module.
|
|
319
|
+
registry_config: Registry config (client_config) forwarded from the main process.
|
|
186
320
|
context: Allow TaskIQ context access
|
|
187
321
|
"""
|
|
188
322
|
logger.info("Starting module with services_mode: %s", services_mode)
|
|
323
|
+
|
|
324
|
+
# Restore registry config lost during pickle (worker re-imports class without runtime mutations)
|
|
325
|
+
if registry_config is not None:
|
|
326
|
+
if "services_config_params" not in module_class.__dict__:
|
|
327
|
+
module_class.services_config_params = dict(module_class.services_config_params)
|
|
328
|
+
module_class.services_config_params["registry"] = registry_config
|
|
329
|
+
|
|
189
330
|
services_config = ServicesConfig(
|
|
190
331
|
services_config_strategies=module_class.services_config_strategies,
|
|
191
332
|
services_config_params=module_class.services_config_params,
|
|
@@ -219,6 +360,17 @@ async def run_start_module(
|
|
|
219
360
|
setup_model = await module_class.create_setup_model(setup_data)
|
|
220
361
|
except Exception as e:
|
|
221
362
|
logger.error("Failed to reconstruct models for job %s: %s", job_id, e, exc_info=True)
|
|
363
|
+
try:
|
|
364
|
+
await callback(
|
|
365
|
+
ModuleCodeModel(
|
|
366
|
+
code="ValidationError",
|
|
367
|
+
short_description="Model reconstruction failed",
|
|
368
|
+
message=str(e),
|
|
369
|
+
)
|
|
370
|
+
)
|
|
371
|
+
await callback(DataModel(root=EndOfStreamOutput()))
|
|
372
|
+
except Exception:
|
|
373
|
+
logger.exception("Failed to send error to stream for job %s", job_id)
|
|
222
374
|
raise
|
|
223
375
|
|
|
224
376
|
supervisor_task = await executor.execute_task(
|
|
@@ -236,8 +388,19 @@ async def run_start_module(
|
|
|
236
388
|
# Wait for the supervisor task to complete
|
|
237
389
|
await supervisor_task
|
|
238
390
|
logger.info("Module task %s completed", job_id)
|
|
239
|
-
except Exception:
|
|
391
|
+
except Exception as e:
|
|
240
392
|
logger.exception("Error running module %s", job_id)
|
|
393
|
+
try:
|
|
394
|
+
await callback(
|
|
395
|
+
ModuleCodeModel(
|
|
396
|
+
code="WorkerError",
|
|
397
|
+
short_description="Worker execution failed",
|
|
398
|
+
message=str(e),
|
|
399
|
+
)
|
|
400
|
+
)
|
|
401
|
+
await callback(DataModel(root=EndOfStreamOutput()))
|
|
402
|
+
except Exception:
|
|
403
|
+
logger.exception("Failed to send error to stream for job %s", job_id)
|
|
241
404
|
raise
|
|
242
405
|
finally:
|
|
243
406
|
# Cleanup via module context
|
|
@@ -256,6 +419,7 @@ async def run_config_module(
|
|
|
256
419
|
services_mode: ServicesMode,
|
|
257
420
|
config_setup_data: dict,
|
|
258
421
|
request_metadata: dict[str, str] | None = None,
|
|
422
|
+
registry_config: dict[str, Any] | None = None,
|
|
259
423
|
context: Context = TaskiqDepends(),
|
|
260
424
|
) -> None:
|
|
261
425
|
"""TaskIQ task allowing a module to compute in the background asynchronously.
|
|
@@ -268,9 +432,17 @@ async def run_config_module(
|
|
|
268
432
|
services_mode: ServicesMode,
|
|
269
433
|
config_setup_data: dict,
|
|
270
434
|
request_metadata: gRPC request metadata (headers) to forward to the module.
|
|
435
|
+
registry_config: Registry config (client_config) forwarded from the main process.
|
|
271
436
|
context: Allow TaskIQ context access
|
|
272
437
|
"""
|
|
273
438
|
logger.info("Starting config module with services_mode: %s", services_mode)
|
|
439
|
+
|
|
440
|
+
# Restore registry config lost during pickle (worker re-imports class without runtime mutations)
|
|
441
|
+
if registry_config is not None:
|
|
442
|
+
if "services_config_params" not in module_class.__dict__:
|
|
443
|
+
module_class.services_config_params = dict(module_class.services_config_params)
|
|
444
|
+
module_class.services_config_params["registry"] = registry_config
|
|
445
|
+
|
|
274
446
|
services_config = ServicesConfig(
|
|
275
447
|
services_config_strategies=module_class.services_config_strategies,
|
|
276
448
|
services_config_params=module_class.services_config_params,
|
|
@@ -293,7 +465,22 @@ async def run_config_module(
|
|
|
293
465
|
session = TaskSession(job_id, mission_id, module)
|
|
294
466
|
|
|
295
467
|
# Create and run the config setup task with TaskExecutor
|
|
296
|
-
|
|
468
|
+
try:
|
|
469
|
+
setup_model = module_class.create_config_setup_model(config_setup_data)
|
|
470
|
+
except Exception as e:
|
|
471
|
+
logger.error("Failed to reconstruct config setup model for job %s: %s", job_id, e, exc_info=True)
|
|
472
|
+
try:
|
|
473
|
+
await callback(
|
|
474
|
+
ModuleCodeModel(
|
|
475
|
+
code="ValidationError",
|
|
476
|
+
short_description="Config setup model reconstruction failed",
|
|
477
|
+
message=str(e),
|
|
478
|
+
)
|
|
479
|
+
)
|
|
480
|
+
await callback(DataModel(root=EndOfStreamOutput()))
|
|
481
|
+
except Exception:
|
|
482
|
+
logger.exception("Failed to send error to stream for job %s", job_id)
|
|
483
|
+
raise
|
|
297
484
|
|
|
298
485
|
supervisor_task = await executor.execute_task(
|
|
299
486
|
task_id=job_id,
|
|
@@ -305,8 +492,19 @@ async def run_config_module(
|
|
|
305
492
|
# Wait for the supervisor task to complete
|
|
306
493
|
await supervisor_task
|
|
307
494
|
logger.info("Config module task %s completed", job_id)
|
|
308
|
-
except Exception:
|
|
495
|
+
except Exception as e:
|
|
309
496
|
logger.exception("Error running config module %s", job_id)
|
|
497
|
+
try:
|
|
498
|
+
await callback(
|
|
499
|
+
ModuleCodeModel(
|
|
500
|
+
code="WorkerError",
|
|
501
|
+
short_description="Config worker execution failed",
|
|
502
|
+
message=str(e),
|
|
503
|
+
)
|
|
504
|
+
)
|
|
505
|
+
await callback(DataModel(root=EndOfStreamOutput()))
|
|
506
|
+
except Exception:
|
|
507
|
+
logger.exception("Failed to send error to stream for job %s", job_id)
|
|
310
508
|
raise
|
|
311
509
|
finally:
|
|
312
510
|
# Cleanup via module context
|