digitalkin 0.3.3.dev9__tar.gz → 0.3.5.dev0__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.3.dev9 → digitalkin-0.3.5.dev0}/PKG-INFO +2 -2
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/archetype_with_tools_module.py +3 -2
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/pyproject.toml +3 -3
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/__version__.py +1 -1
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/_base_server.py +56 -48
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/module_server.py +7 -11
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +9 -9
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/grpc_servers/models.py +2 -154
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/__init__.py +1 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/server/__init__.py +1 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/server/channel.py +36 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/server/grpc.py +99 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/server/server.py +47 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/utils/__init__.py +1 -0
- digitalkin-0.3.5.dev0/src/digitalkin/models/settings/utils/channel.py +148 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin.egg-info/PKG-INFO +2 -2
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin.egg-info/SOURCES.txt +7 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin.egg-info/requires.txt +1 -1
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/LICENSE +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/README.md +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/mock/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/server_async_insecure.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/server_async_secure.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/server_sync_insecure.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/base_server/server_sync_secure.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/cpu_intensive_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/dynamic_setup_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/minimal_llm_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/modules/text_transform_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/monitoring/tests/test_metrics.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/services/filesystem_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/examples/services/storage_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/setup.cfg +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/common/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/common/factories.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/profiling/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/profiling/asyncio_monitor.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/profiling/task_profiler.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/task_executor.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/core/task_manager/task_session.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/logger.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/callback_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/core/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/base_types.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/module_context.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/module_types.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/request_metadata.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/select_schema.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/setup_types.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/tool_cache.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/tool_reference.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/module/utility.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/services/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/services/cost.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/services/registry.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/services/storage.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/_base_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/archetype_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/tool_module.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/trigger_handler.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/triggers/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/py.typed +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/agent/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/agent/agent_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/agent/default_agent.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/base_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/communication/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/communication/communication_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/communication/default_communication.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/communication/grpc_communication.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/cost/grpc_cost.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/identity/default_identity.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/default_registry.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/exceptions.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/grpc_registry.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/registry_models.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/registry/registry_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/services_config.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/services_models.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/setup/default_setup.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/setup/grpc_setup.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/setup/setup_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/snapshot/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/storage/default_storage.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/storage/grpc_storage.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/task_manager/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/task_manager/grpc_task_manager.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/user_profile/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/__init__.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/arg_parser.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/conditional_schema.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/development_mode_action.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/dynamic_schema.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/llm_ready_schema.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/package_discover.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/proto_utils.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/utils/schema_splitter.py +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
- {digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/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.
|
|
3
|
+
Version: 0.3.5.dev0
|
|
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
|
|
@@ -453,7 +453,7 @@ Requires-Python: >=3.10
|
|
|
453
453
|
Description-Content-Type: text/markdown
|
|
454
454
|
License-File: LICENSE
|
|
455
455
|
Requires-Dist: agentic-mesh-protocol==0.2.3
|
|
456
|
-
Requires-Dist: anyio==4.
|
|
456
|
+
Requires-Dist: anyio==4.13.0
|
|
457
457
|
Requires-Dist: grpcio-health-checking==1.78.0
|
|
458
458
|
Requires-Dist: grpcio-reflection==1.78.0
|
|
459
459
|
Requires-Dist: grpcio-status==1.78.0
|
{digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/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
|
)
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
dependencies = [
|
|
30
30
|
"agentic-mesh-protocol==0.2.3",
|
|
31
|
-
"anyio==4.
|
|
31
|
+
"anyio==4.13.0",
|
|
32
32
|
"grpcio-health-checking==1.78.0",
|
|
33
33
|
"grpcio-reflection==1.78.0",
|
|
34
34
|
"grpcio-status==1.78.0",
|
|
35
35
|
"pydantic==2.12.5",
|
|
36
36
|
]
|
|
37
|
-
version = "0.3.
|
|
37
|
+
version = "0.3.5.dev0"
|
|
38
38
|
|
|
39
39
|
[project.optional-dependencies]
|
|
40
40
|
profiling = [
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
|
|
61
61
|
[dependency-groups]
|
|
62
62
|
dev = [
|
|
63
|
-
"build==1.4.
|
|
63
|
+
"build==1.4.1",
|
|
64
64
|
"bump-my-version==1.2.7",
|
|
65
65
|
"cryptography==46.0.5",
|
|
66
66
|
"mypy==1.19.1",
|
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
from collections.abc import Callable, Sequence
|
|
7
7
|
from concurrent import futures
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Any, cast
|
|
9
|
+
from typing import Any, ClassVar, cast
|
|
10
10
|
|
|
11
11
|
import grpc
|
|
12
12
|
from grpc import aio as grpc_aio
|
|
@@ -20,8 +20,9 @@ from digitalkin.grpc_servers.utils.exceptions import (
|
|
|
20
20
|
)
|
|
21
21
|
from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
|
|
22
22
|
from digitalkin.logger import logger
|
|
23
|
-
from digitalkin.models.grpc_servers.models import SecurityMode, ServerConfig, ServerMode
|
|
24
23
|
from digitalkin.models.grpc_servers.types import GrpcServer, ServiceDescriptor, T
|
|
24
|
+
from digitalkin.models.settings.server.server import ServerSettings
|
|
25
|
+
from digitalkin.models.settings.utils.channel import ControlFlow, SecurityMode
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class BaseServer(abc.ABC):
|
|
@@ -32,25 +33,23 @@ class BaseServer(abc.ABC):
|
|
|
32
33
|
communication modes.
|
|
33
34
|
|
|
34
35
|
Attributes:
|
|
35
|
-
config: The server configuration.
|
|
36
36
|
server: The gRPC server instance (either sync or async).
|
|
37
37
|
_servicers: List of registered servicers.
|
|
38
38
|
_service_names: List of service names for reflection.
|
|
39
39
|
_health_servicer: Optional health check servicer.
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
+
_server_settings: ClassVar[ServerSettings] = ServerSettings()
|
|
43
|
+
|
|
42
44
|
def __init__(
|
|
43
45
|
self,
|
|
44
|
-
config: ServerConfig,
|
|
45
46
|
interceptors: Sequence[Any] | None = None,
|
|
46
47
|
) -> None:
|
|
47
48
|
"""Initialize the base gRPC server.
|
|
48
49
|
|
|
49
50
|
Args:
|
|
50
|
-
config: The server configuration.
|
|
51
51
|
interceptors: Optional sequence of gRPC server interceptors.
|
|
52
52
|
"""
|
|
53
|
-
self.config = config
|
|
54
53
|
self.server: GrpcServer | None = None
|
|
55
54
|
self._servicers: list[Any] = []
|
|
56
55
|
self._service_names: list[str] = [] # Track service names for reflection
|
|
@@ -119,7 +118,7 @@ class BaseServer(abc.ABC):
|
|
|
119
118
|
Raises:
|
|
120
119
|
ReflectionError: If reflection initialization fails.
|
|
121
120
|
"""
|
|
122
|
-
if not self.
|
|
121
|
+
if not self._server_settings.reflection or self.server is None or not self._service_names:
|
|
123
122
|
return
|
|
124
123
|
|
|
125
124
|
try:
|
|
@@ -194,17 +193,17 @@ class BaseServer(abc.ABC):
|
|
|
194
193
|
logger.warning("Failed to enable health service: %s", e)
|
|
195
194
|
|
|
196
195
|
def _create_server(self) -> GrpcServer:
|
|
197
|
-
"""Create a gRPC server instance based on the
|
|
196
|
+
"""Create a gRPC server instance based on the server settings.
|
|
198
197
|
|
|
199
198
|
Returns:
|
|
200
199
|
A configured gRPC server instance.
|
|
201
200
|
|
|
202
201
|
Raises:
|
|
203
|
-
ConfigurationError: If the server
|
|
202
|
+
ConfigurationError: If the server settings are invalid.
|
|
204
203
|
"""
|
|
205
204
|
try:
|
|
206
205
|
# Create the server based on mode
|
|
207
|
-
grpc_compression = self.
|
|
206
|
+
grpc_compression = self._server_settings.grpc.compression.to_grpc()
|
|
208
207
|
|
|
209
208
|
# Machine capabilities
|
|
210
209
|
try:
|
|
@@ -215,36 +214,36 @@ class BaseServer(abc.ABC):
|
|
|
215
214
|
logger.info("CPU count: %d", cpu_count)
|
|
216
215
|
|
|
217
216
|
# Compute defaults from machine capabilities, overridable via env vars
|
|
218
|
-
max_concurrent_rpcs = int(os.environ.get("DIGITALKIN_MAX_CONCURRENT_RPCS", str(cpu_count * 200)))
|
|
219
|
-
thread_pool_workers = int(os.environ.get("DIGITALKIN_THREAD_POOL_WORKERS", str(min(4, cpu_count))))
|
|
220
217
|
|
|
221
218
|
logger.info(
|
|
222
|
-
"gRPC server
|
|
219
|
+
"gRPC server settings.server: cpus=%d, max_concurrent_rpcs=%d, thread_pool_workers=%d, mode=%s",
|
|
223
220
|
cpu_count,
|
|
224
|
-
max_concurrent_rpcs,
|
|
225
|
-
thread_pool_workers,
|
|
226
|
-
self.
|
|
221
|
+
self._server_settings.max_concurrent_rpcs,
|
|
222
|
+
self._server_settings.thread_pool_workers,
|
|
223
|
+
self._server_settings.channel.communication_mode.value,
|
|
227
224
|
)
|
|
228
225
|
|
|
229
|
-
if self.
|
|
226
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
230
227
|
server = grpc_aio.server(
|
|
231
|
-
options=self.
|
|
228
|
+
options=self._server_settings.grpc.options,
|
|
232
229
|
compression=grpc_compression,
|
|
233
230
|
interceptors=self._interceptors or None,
|
|
234
|
-
maximum_concurrent_rpcs=max_concurrent_rpcs,
|
|
235
|
-
migration_thread_pool=futures.ThreadPoolExecutor(
|
|
231
|
+
maximum_concurrent_rpcs=self._server_settings.max_concurrent_rpcs,
|
|
232
|
+
migration_thread_pool=futures.ThreadPoolExecutor(
|
|
233
|
+
max_workers=self._server_settings.thread_pool_workers
|
|
234
|
+
),
|
|
236
235
|
)
|
|
237
236
|
else:
|
|
238
237
|
server = grpc.server( # type: ignore[assignment] # sync grpc.Server assigned to GrpcServer union
|
|
239
|
-
futures.ThreadPoolExecutor(max_workers=self.
|
|
240
|
-
options=self.
|
|
238
|
+
futures.ThreadPoolExecutor(max_workers=self._server_settings.max_workers),
|
|
239
|
+
options=self._server_settings.grpc.options,
|
|
241
240
|
compression=grpc_compression,
|
|
242
241
|
interceptors=self._interceptors or None,
|
|
243
|
-
maximum_concurrent_rpcs=max_concurrent_rpcs,
|
|
242
|
+
maximum_concurrent_rpcs=self._server_settings.max_concurrent_rpcs,
|
|
244
243
|
)
|
|
245
244
|
|
|
246
245
|
# Add the appropriate port
|
|
247
|
-
if self.
|
|
246
|
+
if self._server_settings.channel.security == SecurityMode.SECURE:
|
|
248
247
|
self._add_secure_port(server)
|
|
249
248
|
else:
|
|
250
249
|
self._add_insecure_port(server)
|
|
@@ -264,19 +263,26 @@ class BaseServer(abc.ABC):
|
|
|
264
263
|
Raises:
|
|
265
264
|
SecurityError: If credentials are not configured correctly.
|
|
266
265
|
"""
|
|
267
|
-
if not self.
|
|
266
|
+
if not self._server_settings.channel.credentials:
|
|
268
267
|
msg = "Credentials must be provided for secure server"
|
|
269
268
|
raise SecurityError(msg)
|
|
270
269
|
|
|
271
270
|
try:
|
|
272
271
|
# Read key and certificate files
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
if (
|
|
273
|
+
self._server_settings.channel.credentials.key_path
|
|
274
|
+
and self._server_settings.channel.credentials.cert_path
|
|
275
|
+
):
|
|
276
|
+
private_key = Path(self._server_settings.channel.credentials.key_path).read_bytes()
|
|
277
|
+
certificate_chain = Path(self._server_settings.channel.credentials.cert_path).read_bytes()
|
|
278
|
+
else:
|
|
279
|
+
msg = "Key path and certificate path must be provided for secure server"
|
|
280
|
+
raise SecurityError(msg)
|
|
275
281
|
|
|
276
282
|
# Read root certificate if provided
|
|
277
283
|
root_certificates = None
|
|
278
|
-
if self.
|
|
279
|
-
root_certificates = Path(self.
|
|
284
|
+
if self._server_settings.channel.credentials.root_cert_path:
|
|
285
|
+
root_certificates = Path(self._server_settings.channel.credentials.root_cert_path).read_bytes()
|
|
280
286
|
except OSError as e:
|
|
281
287
|
msg = f"Failed to read credential files: {e}"
|
|
282
288
|
raise SecurityError(msg) from e
|
|
@@ -290,16 +296,16 @@ class BaseServer(abc.ABC):
|
|
|
290
296
|
)
|
|
291
297
|
|
|
292
298
|
# Add secure port to server
|
|
293
|
-
if self.
|
|
299
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
294
300
|
async_server = cast("grpc_aio.Server", server)
|
|
295
|
-
async_server.add_secure_port(self.
|
|
301
|
+
async_server.add_secure_port(self._server_settings.channel.address, server_credentials)
|
|
296
302
|
else:
|
|
297
303
|
sync_server = cast("grpc.Server", server)
|
|
298
|
-
sync_server.add_secure_port(self.
|
|
304
|
+
sync_server.add_secure_port(self._server_settings.channel.address, server_credentials)
|
|
299
305
|
|
|
300
|
-
logger.debug("Added secure port %s", self.
|
|
306
|
+
logger.debug("Added secure port %s", self._server_settings.channel.address)
|
|
301
307
|
except Exception as e:
|
|
302
|
-
msg = f"Failed to configure secure port: {e}"
|
|
308
|
+
msg = f"Failed to configure with actual settings secure port: {e}"
|
|
303
309
|
raise SecurityError(msg) from e
|
|
304
310
|
|
|
305
311
|
def _add_insecure_port(self, server: GrpcServer) -> None:
|
|
@@ -312,14 +318,14 @@ class BaseServer(abc.ABC):
|
|
|
312
318
|
ConfigurationError: If adding the insecure port fails.
|
|
313
319
|
"""
|
|
314
320
|
try:
|
|
315
|
-
if self.
|
|
321
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
316
322
|
async_server = cast("grpc_aio.Server", server)
|
|
317
|
-
async_server.add_insecure_port(self.
|
|
323
|
+
async_server.add_insecure_port(self._server_settings.channel.address)
|
|
318
324
|
else:
|
|
319
325
|
sync_server = cast("grpc.Server", server)
|
|
320
|
-
sync_server.add_insecure_port(self.
|
|
326
|
+
sync_server.add_insecure_port(self._server_settings.channel.address)
|
|
321
327
|
|
|
322
|
-
logger.debug("Added insecure port %s", self.
|
|
328
|
+
logger.debug("Added insecure port %s", self._server_settings.channel.address)
|
|
323
329
|
except Exception as e:
|
|
324
330
|
msg = f"Failed to add insecure port: {e}"
|
|
325
331
|
raise ConfigurationError(msg) from e
|
|
@@ -343,9 +349,11 @@ class BaseServer(abc.ABC):
|
|
|
343
349
|
self._add_reflection()
|
|
344
350
|
|
|
345
351
|
# Start the server
|
|
346
|
-
logger.debug(
|
|
352
|
+
logger.debug(
|
|
353
|
+
"Starting gRPC server on %s", self._server_settings.channel.address, extra={"config": ServerSettings}
|
|
354
|
+
)
|
|
347
355
|
try:
|
|
348
|
-
if self.
|
|
356
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
349
357
|
# For async server, use the event loop
|
|
350
358
|
loop = asyncio.get_event_loop()
|
|
351
359
|
if loop.is_closed():
|
|
@@ -356,7 +364,7 @@ class BaseServer(abc.ABC):
|
|
|
356
364
|
# For sync server, directly call start
|
|
357
365
|
sync_server = cast("grpc.Server", self.server)
|
|
358
366
|
sync_server.start()
|
|
359
|
-
logger.debug("✅ gRPC server started on %s", self.
|
|
367
|
+
logger.debug("✅ gRPC server started on %s", self._server_settings.channel.address)
|
|
360
368
|
except Exception as e:
|
|
361
369
|
logger.exception("❎ Error starting server")
|
|
362
370
|
msg = f"Failed to start server: {e}"
|
|
@@ -393,15 +401,15 @@ class BaseServer(abc.ABC):
|
|
|
393
401
|
self._add_reflection()
|
|
394
402
|
|
|
395
403
|
# Start the server
|
|
396
|
-
logger.debug("Starting gRPC server on %s", self.
|
|
404
|
+
logger.debug("Starting gRPC server on %s", self._server_settings.channel.address)
|
|
397
405
|
try:
|
|
398
|
-
if self.
|
|
406
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
399
407
|
await self._start_async()
|
|
400
408
|
else:
|
|
401
409
|
# For sync server in async context
|
|
402
410
|
sync_server = cast("grpc.Server", self.server)
|
|
403
411
|
sync_server.start()
|
|
404
|
-
logger.debug("✅ gRPC server started on %s", self.
|
|
412
|
+
logger.debug("✅ gRPC server started on %s", self._server_settings.channel.address)
|
|
405
413
|
except Exception as e:
|
|
406
414
|
logger.exception("❎ Error starting server")
|
|
407
415
|
msg = f"Failed to start server: {e}"
|
|
@@ -431,7 +439,7 @@ class BaseServer(abc.ABC):
|
|
|
431
439
|
return
|
|
432
440
|
|
|
433
441
|
logger.debug("Stopping gRPC server...")
|
|
434
|
-
if self.
|
|
442
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
435
443
|
# We'll use a different approach that works whether we're in a running event loop or not
|
|
436
444
|
try:
|
|
437
445
|
# Get the current event loop
|
|
@@ -507,7 +515,7 @@ class BaseServer(abc.ABC):
|
|
|
507
515
|
return
|
|
508
516
|
|
|
509
517
|
logger.debug("Stopping gRPC server asynchronously...")
|
|
510
|
-
if self.
|
|
518
|
+
if self._server_settings.channel.communication_mode == ControlFlow.ASYNC:
|
|
511
519
|
await self._stop_async(grace)
|
|
512
520
|
else:
|
|
513
521
|
# For sync server, we can just call stop
|
|
@@ -533,7 +541,7 @@ class BaseServer(abc.ABC):
|
|
|
533
541
|
logger.warning("Attempted to wait for termination, but no server is running")
|
|
534
542
|
return
|
|
535
543
|
|
|
536
|
-
if self.
|
|
544
|
+
if self._server_settings.channel.communication_mode == ControlFlow.SYNC:
|
|
537
545
|
# For sync server
|
|
538
546
|
sync_server = cast("grpc.Server", self.server)
|
|
539
547
|
sync_server.wait_for_termination()
|
|
@@ -548,7 +556,7 @@ class BaseServer(abc.ABC):
|
|
|
548
556
|
|
|
549
557
|
This method should only be used with async servers.
|
|
550
558
|
"""
|
|
551
|
-
if self.
|
|
559
|
+
if self._server_settings.channel.communication_mode == ControlFlow.SYNC:
|
|
552
560
|
logger.warning(
|
|
553
561
|
"Called await_termination on sync server. Use wait_for_termination instead for sync servers.",
|
|
554
562
|
)
|
{digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/grpc_servers/module_server.py
RENAMED
|
@@ -13,7 +13,6 @@ from digitalkin.grpc_servers.module_servicer import ModuleServicer
|
|
|
13
13
|
from digitalkin.logger import logger
|
|
14
14
|
from digitalkin.models.grpc_servers.models import (
|
|
15
15
|
ClientConfig,
|
|
16
|
-
ModuleServerConfig,
|
|
17
16
|
)
|
|
18
17
|
from digitalkin.modules._base_module import BaseModule
|
|
19
18
|
from digitalkin.services.registry import GrpcRegistry
|
|
@@ -38,7 +37,6 @@ class ModuleServer(BaseServer):
|
|
|
38
37
|
def __init__(
|
|
39
38
|
self,
|
|
40
39
|
module_class: type[BaseModule],
|
|
41
|
-
server_config: ModuleServerConfig,
|
|
42
40
|
client_config: ClientConfig | None = None,
|
|
43
41
|
interceptors: Sequence[Any] | None = None,
|
|
44
42
|
) -> None:
|
|
@@ -46,13 +44,11 @@ class ModuleServer(BaseServer):
|
|
|
46
44
|
|
|
47
45
|
Args:
|
|
48
46
|
module_class: The module instance to be served.
|
|
49
|
-
server_config: Server configuration.
|
|
50
47
|
client_config: Client configuration used by services and registry connection.
|
|
51
48
|
interceptors: Optional sequence of gRPC server interceptors.
|
|
52
49
|
"""
|
|
53
|
-
super().__init__(
|
|
50
|
+
super().__init__(interceptors=interceptors)
|
|
54
51
|
self.module_class = module_class
|
|
55
|
-
self.server_config = server_config
|
|
56
52
|
self.client_config = client_config
|
|
57
53
|
self.module_servicer: ModuleServicer | None = None
|
|
58
54
|
self.registry: RegistryStrategy | None = None
|
|
@@ -108,7 +104,7 @@ class ModuleServer(BaseServer):
|
|
|
108
104
|
"""Start the module server and register with the registry if configured."""
|
|
109
105
|
import asyncio
|
|
110
106
|
|
|
111
|
-
logger.info("Starting module server", extra={"server_config": self.
|
|
107
|
+
logger.info("Starting module server", extra={"server_config": self._server_settings})
|
|
112
108
|
super().start()
|
|
113
109
|
|
|
114
110
|
try:
|
|
@@ -119,7 +115,7 @@ class ModuleServer(BaseServer):
|
|
|
119
115
|
|
|
120
116
|
async def start_async(self) -> None:
|
|
121
117
|
"""Start the module server and register with the registry if configured."""
|
|
122
|
-
logger.info("Starting module server", extra={"server_config": self.
|
|
118
|
+
logger.info("Starting module server", extra={"server_config": self._server_settings})
|
|
123
119
|
await super().start_async()
|
|
124
120
|
|
|
125
121
|
# module_servicer is now set by _register_servicers() during super().start_async()
|
|
@@ -191,14 +187,14 @@ class ModuleServer(BaseServer):
|
|
|
191
187
|
)
|
|
192
188
|
return
|
|
193
189
|
|
|
194
|
-
advertise_address = self.
|
|
190
|
+
advertise_address = self._server_settings.channel.advertise_host or self._server_settings.channel.host
|
|
195
191
|
|
|
196
192
|
logger.info(
|
|
197
193
|
"Attempting to register module with registry",
|
|
198
194
|
extra={
|
|
199
195
|
"module_id": module_id,
|
|
200
196
|
"address": advertise_address,
|
|
201
|
-
"port": self.
|
|
197
|
+
"port": self._server_settings.channel.port,
|
|
202
198
|
"version": version,
|
|
203
199
|
},
|
|
204
200
|
)
|
|
@@ -206,7 +202,7 @@ class ModuleServer(BaseServer):
|
|
|
206
202
|
result = await self.registry.register(
|
|
207
203
|
module_id=module_id,
|
|
208
204
|
address=advertise_address,
|
|
209
|
-
port=self.
|
|
205
|
+
port=self._server_settings.channel.port,
|
|
210
206
|
version=version,
|
|
211
207
|
)
|
|
212
208
|
|
|
@@ -216,7 +212,7 @@ class ModuleServer(BaseServer):
|
|
|
216
212
|
extra={
|
|
217
213
|
"module_id": result.module_id,
|
|
218
214
|
"address": advertise_address,
|
|
219
|
-
"port": self.
|
|
215
|
+
"port": self._server_settings.channel.port,
|
|
220
216
|
},
|
|
221
217
|
)
|
|
222
218
|
else:
|
|
@@ -11,7 +11,8 @@ import grpc.aio
|
|
|
11
11
|
|
|
12
12
|
from digitalkin.grpc_servers.utils.exceptions import ServerError
|
|
13
13
|
from digitalkin.logger import logger
|
|
14
|
-
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
14
|
+
from digitalkin.models.grpc_servers.models import ClientConfig
|
|
15
|
+
from digitalkin.models.settings.utils.channel import SecurityMode
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class GrpcClientWrapper:
|
|
@@ -31,6 +32,13 @@ class GrpcClientWrapper:
|
|
|
31
32
|
_channel_cache_key: str | None = None
|
|
32
33
|
_channel_cache: ClassVar[dict[str, grpc.aio.Channel]] = {}
|
|
33
34
|
_ref_counts: ClassVar[dict[str, int]] = {}
|
|
35
|
+
_RETRYABLE_CODES: ClassVar[set[grpc.StatusCode]] = {
|
|
36
|
+
grpc.StatusCode.UNAVAILABLE,
|
|
37
|
+
grpc.StatusCode.INTERNAL,
|
|
38
|
+
grpc.StatusCode.DEADLINE_EXCEEDED,
|
|
39
|
+
}
|
|
40
|
+
_QUERY_MAX_RETRIES: ClassVar[int] = int(os.environ.get("DIGITALKIN_GRPC_QUERY_MAX_RETRIES", "2"))
|
|
41
|
+
_QUERY_BACKOFF_BASE_MS: ClassVar[float] = float(os.environ.get("DIGITALKIN_GRPC_QUERY_BACKOFF_BASE_MS", "50"))
|
|
34
42
|
|
|
35
43
|
@staticmethod
|
|
36
44
|
def _build_channel_credentials(config: ClientConfig) -> grpc.ChannelCredentials | None:
|
|
@@ -140,14 +148,6 @@ class GrpcClientWrapper:
|
|
|
140
148
|
cls._channel_cache.clear()
|
|
141
149
|
cls._ref_counts.clear()
|
|
142
150
|
|
|
143
|
-
_RETRYABLE_CODES: ClassVar[set[grpc.StatusCode]] = {
|
|
144
|
-
grpc.StatusCode.UNAVAILABLE,
|
|
145
|
-
grpc.StatusCode.INTERNAL,
|
|
146
|
-
grpc.StatusCode.DEADLINE_EXCEEDED,
|
|
147
|
-
}
|
|
148
|
-
_QUERY_MAX_RETRIES: ClassVar[int] = int(os.environ.get("DIGITALKIN_GRPC_QUERY_MAX_RETRIES", "2"))
|
|
149
|
-
_QUERY_BACKOFF_BASE_MS: ClassVar[float] = float(os.environ.get("DIGITALKIN_GRPC_QUERY_BACKOFF_BASE_MS", "50"))
|
|
150
|
-
|
|
151
151
|
async def exec_grpc_query(
|
|
152
152
|
self,
|
|
153
153
|
query_endpoint: str,
|
{digitalkin-0.3.3.dev9 → digitalkin-0.3.5.dev0}/src/digitalkin/models/grpc_servers/models.py
RENAMED
|
@@ -9,6 +9,7 @@ import grpc
|
|
|
9
9
|
from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
|
10
10
|
|
|
11
11
|
from digitalkin.grpc_servers.utils.exceptions import ConfigurationError, SecurityError
|
|
12
|
+
from digitalkin.models.settings.utils.channel import ControlFlow, SecurityMode
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class GrpcCompression(str, Enum):
|
|
@@ -39,61 +40,6 @@ class GrpcCompression(str, Enum):
|
|
|
39
40
|
return grpc.Compression.Deflate
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
class ServerMode(str, Enum):
|
|
43
|
-
"""Enum for server operation mode."""
|
|
44
|
-
|
|
45
|
-
SYNC = "sync"
|
|
46
|
-
ASYNC = "async"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class SecurityMode(str, Enum):
|
|
50
|
-
"""Enum for server security mode."""
|
|
51
|
-
|
|
52
|
-
SECURE = "secure"
|
|
53
|
-
INSECURE = "insecure"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class ServerCredentials(BaseModel):
|
|
57
|
-
"""Model for server credentials in secure mode.
|
|
58
|
-
|
|
59
|
-
Attributes:
|
|
60
|
-
server_key_path: Path to the server private key
|
|
61
|
-
server_cert_path: Path to the server certificate
|
|
62
|
-
root_cert_path: Optional path to the root certificate
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
server_key_path: Path = Field(..., description="Path to the server private key")
|
|
66
|
-
server_cert_path: Path = Field(..., description="Path to the server certificate")
|
|
67
|
-
root_cert_path: Path | None = Field(None, description="Path to the root certificate")
|
|
68
|
-
|
|
69
|
-
# Enable __slots__ for memory efficiency
|
|
70
|
-
model_config = {
|
|
71
|
-
"extra": "forbid",
|
|
72
|
-
"arbitrary_types_allowed": True,
|
|
73
|
-
"validate_assignment": True,
|
|
74
|
-
"frozen": True,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
@field_validator("server_key_path", "server_cert_path", "root_cert_path")
|
|
78
|
-
@classmethod
|
|
79
|
-
def check_path_exists(cls, v: Path | None) -> Path | None:
|
|
80
|
-
"""Validate that the file path exists.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
v: Path to validate
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
The validated path
|
|
87
|
-
|
|
88
|
-
Raises:
|
|
89
|
-
SecurityError: If the path does not exist
|
|
90
|
-
"""
|
|
91
|
-
if v is not None and not v.exists():
|
|
92
|
-
msg = f"File not found: {v}"
|
|
93
|
-
raise SecurityError(msg)
|
|
94
|
-
return v
|
|
95
|
-
|
|
96
|
-
|
|
97
43
|
class RetryPolicy(BaseModel):
|
|
98
44
|
"""gRPC retry policy configuration for resilient connections.
|
|
99
45
|
|
|
@@ -202,7 +148,7 @@ class ChannelConfig(BaseModel):
|
|
|
202
148
|
description="Host address to bind the client to",
|
|
203
149
|
) # Bind to all interfaces by design
|
|
204
150
|
port: int = Field(50051, description="Port to listen on")
|
|
205
|
-
mode:
|
|
151
|
+
mode: ControlFlow = Field(ControlFlow.SYNC, description="Client operation mode (sync/async)")
|
|
206
152
|
security: SecurityMode = Field(SecurityMode.INSECURE, description="Security mode (secure/insecure)")
|
|
207
153
|
|
|
208
154
|
# Enable __slots__ for memory efficiency
|
|
@@ -315,101 +261,3 @@ class ClientConfig(ChannelConfig):
|
|
|
315
261
|
Full list of gRPC channel options.
|
|
316
262
|
"""
|
|
317
263
|
return [*self.channel_options, ("grpc.service_config", self.retry_policy.to_service_config_json())]
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
class ServerConfig(ChannelConfig):
|
|
321
|
-
"""Base configuration for gRPC servers.
|
|
322
|
-
|
|
323
|
-
Attributes:
|
|
324
|
-
host: Host address to bind the server to
|
|
325
|
-
port: Port to listen on
|
|
326
|
-
max_workers: Maximum number of workers for sync mode
|
|
327
|
-
mode: Server operation mode (sync/async)
|
|
328
|
-
security: Security mode (secure/insecure)
|
|
329
|
-
credentials: Server credentials for secure mode
|
|
330
|
-
server_options: Additional server options
|
|
331
|
-
enable_reflection: Enable reflection for the server
|
|
332
|
-
compression: gRPC compression algorithm for server-level compression
|
|
333
|
-
"""
|
|
334
|
-
|
|
335
|
-
max_workers: int = Field(10, description="Maximum number of workers for sync mode")
|
|
336
|
-
credentials: ServerCredentials | None = Field(None, description="Server credentials for secure mode")
|
|
337
|
-
compression: GrpcCompression = Field(GrpcCompression.GZIP, description="gRPC compression algorithm")
|
|
338
|
-
server_options: list[tuple[str, Any]] = Field(
|
|
339
|
-
default_factory=lambda: [
|
|
340
|
-
("grpc.max_receive_message_length", 100 * 1024 * 1024),
|
|
341
|
-
("grpc.max_send_message_length", 100 * 1024 * 1024),
|
|
342
|
-
# === Server-Side Keepalive (Keeps Connections Alive Through Proxies) ===
|
|
343
|
-
# Server sends keepalive pings to detect dead clients and keep
|
|
344
|
-
# proxy connections (e.g. Railway) alive during long-running RPCs.
|
|
345
|
-
(
|
|
346
|
-
"grpc.keepalive_time_ms",
|
|
347
|
-
int(os.environ.get("DIGITALKIN_GRPC_SERVER_KEEPALIVE_TIME_MS", "120000")),
|
|
348
|
-
),
|
|
349
|
-
(
|
|
350
|
-
"grpc.keepalive_timeout_ms",
|
|
351
|
-
int(os.environ.get("DIGITALKIN_GRPC_SERVER_KEEPALIVE_TIMEOUT_MS", "20000")),
|
|
352
|
-
),
|
|
353
|
-
# === Keepalive Permission (Required for Client Keepalive) ===
|
|
354
|
-
# Allow clients to send keepalive pings without active RPCs
|
|
355
|
-
# Without this, server rejects client keepalives with GOAWAY
|
|
356
|
-
("grpc.keepalive_permit_without_calls", True),
|
|
357
|
-
# Allow unlimited pings without data (required for long-running streams)
|
|
358
|
-
("grpc.http2.max_pings_without_data", 0),
|
|
359
|
-
# Minimum interval server allows between client pings
|
|
360
|
-
# Prevents "too_many_pings" GOAWAY errors
|
|
361
|
-
# Must match or be less than client's http2.min_time_between_pings_ms
|
|
362
|
-
(
|
|
363
|
-
"grpc.http2.min_ping_interval_without_data_ms",
|
|
364
|
-
int(os.environ.get("DIGITALKIN_GRPC_SERVER_MIN_PING_INTERVAL_MS", "10000")),
|
|
365
|
-
),
|
|
366
|
-
],
|
|
367
|
-
description="gRPC server options with keepalive support",
|
|
368
|
-
)
|
|
369
|
-
enable_reflection: bool = Field(default=True, description="Enable reflection for the server")
|
|
370
|
-
enable_health_check: bool = Field(default=True, description="Enable health check service")
|
|
371
|
-
|
|
372
|
-
@field_validator("credentials")
|
|
373
|
-
@classmethod
|
|
374
|
-
def validate_credentials(cls, v: ServerCredentials | None, info: ValidationInfo) -> ServerCredentials | None:
|
|
375
|
-
"""Validate that credentials are provided when in secure mode.
|
|
376
|
-
|
|
377
|
-
Args:
|
|
378
|
-
v: The credentials value
|
|
379
|
-
info: ValidationInfo containing other field values
|
|
380
|
-
|
|
381
|
-
Returns:
|
|
382
|
-
The validated credentials
|
|
383
|
-
|
|
384
|
-
Raises:
|
|
385
|
-
ConfigurationError: If credentials are missing in secure mode
|
|
386
|
-
"""
|
|
387
|
-
# Access security mode from the info.data dictionary
|
|
388
|
-
security = info.data.get("security")
|
|
389
|
-
|
|
390
|
-
if security == SecurityMode.SECURE and v is None:
|
|
391
|
-
msg = "Credentials must be provided when using secure mode"
|
|
392
|
-
raise ConfigurationError(msg)
|
|
393
|
-
return v
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
class ModuleServerConfig(ServerConfig):
|
|
397
|
-
"""Configuration for Module gRPC server.
|
|
398
|
-
|
|
399
|
-
Attributes:
|
|
400
|
-
advertise_host: Public hostname/IP sent to registry for discovery. Falls back to host if not set.
|
|
401
|
-
"""
|
|
402
|
-
|
|
403
|
-
advertise_host: str | None = Field(
|
|
404
|
-
None, description="Public hostname/IP sent to registry for discovery. Falls back to host if not set."
|
|
405
|
-
)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
class RegistryServerConfig(ServerConfig):
|
|
409
|
-
"""Configuration for Registry gRPC server.
|
|
410
|
-
|
|
411
|
-
Attributes:
|
|
412
|
-
database_url: Database URL for registry data storage
|
|
413
|
-
"""
|
|
414
|
-
|
|
415
|
-
database_url: str | None = Field(None, description="Database URL for registry data storage")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""This package contain settings of sdk."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package for server settings."""
|