digitalkin 1.0.0.dev21__tar.gz → 1.0.0.dev23__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/PKG-INFO +2 -2
  2. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/pyproject.toml +2 -2
  3. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/module_runner.py +4 -0
  5. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/gateway_servicer.py +38 -0
  6. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/module_servicer.py +40 -1
  7. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/stream_error_codes.py +1 -0
  8. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/module_context.py +6 -0
  9. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/communication/grpc_communication.py +35 -11
  10. digitalkin-1.0.0.dev23/src/digitalkin/services/secret/__init__.py +13 -0
  11. digitalkin-1.0.0.dev23/src/digitalkin/services/secret/default_secret.py +45 -0
  12. digitalkin-1.0.0.dev23/src/digitalkin/services/secret/exceptions.py +5 -0
  13. digitalkin-1.0.0.dev23/src/digitalkin/services/secret/grpc_secret.py +63 -0
  14. digitalkin-1.0.0.dev23/src/digitalkin/services/secret/secret_strategy.py +21 -0
  15. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/services_config.py +14 -0
  16. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/services_models.py +2 -0
  17. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/user_profile/default_user_profile.py +12 -0
  18. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/user_profile/grpc_user_profile.py +22 -1
  19. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/user_profile/user_profile_strategy.py +15 -0
  20. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin.egg-info/PKG-INFO +2 -2
  21. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin.egg-info/SOURCES.txt +5 -0
  22. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin.egg-info/requires.txt +1 -1
  23. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/LICENSE +0 -0
  24. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/README.md +0 -0
  25. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/__init__.py +0 -0
  26. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/mock/__init__.py +0 -0
  27. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/mock/mock_pb2.py +0 -0
  28. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  29. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/server_async_insecure.py +0 -0
  30. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/server_async_secure.py +0 -0
  31. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/server_sync_insecure.py +0 -0
  32. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/base_server/server_sync_secure.py +0 -0
  33. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/__init__.py +0 -0
  34. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/echo_module.py +0 -0
  35. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/models/__init__.py +0 -0
  36. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/models/input.py +0 -0
  37. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/models/output.py +0 -0
  38. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/models/secret.py +0 -0
  39. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/models/setup.py +0 -0
  40. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/server.py +0 -0
  41. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/triggers/__init__.py +0 -0
  42. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/bench_module/triggers/message_trigger.py +0 -0
  43. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/__init__.py +0 -0
  44. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/archetype_with_tools_module.py +0 -0
  45. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/cpu_intensive_module.py +0 -0
  46. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/dynamic_setup_module.py +0 -0
  47. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/minimal_llm_module.py +0 -0
  48. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/modules/text_transform_module.py +0 -0
  49. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  50. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  51. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  52. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  53. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  54. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/monitoring/tests/test_metrics.py +0 -0
  55. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/client.py +0 -0
  56. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/echo_module.py +0 -0
  57. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/models/__init__.py +0 -0
  58. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/models/input.py +0 -0
  59. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/models/output.py +0 -0
  60. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/models/secret.py +0 -0
  61. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/models/setup.py +0 -0
  62. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/server.py +0 -0
  63. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/triggers/__init__.py +0 -0
  64. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/redis_demo/triggers/message_trigger.py +0 -0
  65. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/services/filesystem_module.py +0 -0
  66. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/examples/services/storage_module.py +0 -0
  67. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/setup.cfg +0 -0
  68. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/__init__.py +0 -0
  69. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/__init__.py +0 -0
  70. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/agno/__init__.py +0 -0
  71. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/agno/agno_adapter.py +0 -0
  72. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/agno/agui_tools.py +0 -0
  73. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/agno/hitl.py +0 -0
  74. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/community/agno/models.py +0 -0
  75. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/__init__.py +0 -0
  76. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/common/__init__.py +0 -0
  77. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/common/factories.py +0 -0
  78. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/exceptions.py +0 -0
  79. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/job_manager/__init__.py +0 -0
  80. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  81. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  82. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/profiling/__init__.py +0 -0
  83. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/profiling/step_timer.py +0 -0
  84. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/profiling/task_profiler.py +0 -0
  85. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/resilience/__init__.py +0 -0
  86. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  87. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  88. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/__init__.py +0 -0
  89. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  90. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  91. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  92. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
  93. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
  94. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  95. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
  96. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/redis/redis_state.py +0 -0
  97. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  98. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  99. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/core/task_manager/task_session.py +0 -0
  100. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/exceptions.py +0 -0
  101. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/__init__.py +0 -0
  102. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  103. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  104. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  105. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
  106. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
  107. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
  108. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/module_server.py +0 -0
  109. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
  110. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  111. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  112. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  113. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  114. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  115. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  116. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
  117. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/logger.py +0 -0
  118. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/__init__.py +0 -0
  119. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/agui_mixin.py +0 -0
  120. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/base_mixin.py +0 -0
  121. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/cost_mixin.py +0 -0
  122. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  123. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  124. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/logger_mixin.py +0 -0
  125. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/mixins/storage_mixin.py +0 -0
  126. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/__init__.py +0 -0
  127. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/core/__init__.py +0 -0
  128. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/core/job_manager_models.py +0 -0
  129. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/core/redis.py +0 -0
  130. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/core/task_monitor.py +0 -0
  131. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/events/__init__.py +0 -0
  132. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/events/agent_events.py +0 -0
  133. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  134. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  135. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  136. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/models.py +0 -0
  137. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/grpc_servers/types.py +0 -0
  138. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/__init__.py +0 -0
  139. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/ag_ui.py +0 -0
  140. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/base_types.py +0 -0
  141. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/module.py +0 -0
  142. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/module_types.py +0 -0
  143. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/request_metadata.py +0 -0
  144. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/select_schema.py +0 -0
  145. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/setup_types.py +0 -0
  146. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/tool_cache.py +0 -0
  147. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/tool_reference.py +0 -0
  148. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/module/utility.py +0 -0
  149. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/services/__init__.py +0 -0
  150. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/services/cost.py +0 -0
  151. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/services/registry.py +0 -0
  152. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/services/services.py +0 -0
  153. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/services/storage.py +0 -0
  154. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/__init__.py +0 -0
  155. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/gateway.py +0 -0
  156. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/grpc_client.py +0 -0
  157. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/log.py +0 -0
  158. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/module.py +0 -0
  159. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/profiling.py +0 -0
  160. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/queue.py +0 -0
  161. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/redis.py +0 -0
  162. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/resilience.py +0 -0
  163. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/server/__init__.py +0 -0
  164. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/server/channel.py +0 -0
  165. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/server/grpc.py +0 -0
  166. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/server/server.py +0 -0
  167. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/server/servicer.py +0 -0
  168. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/task_manager.py +0 -0
  169. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  170. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/settings/utils/channel.py +0 -0
  171. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/utils/__init__.py +0 -0
  172. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  173. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/__init__.py +0 -0
  174. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/_base_module.py +0 -0
  175. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/archetype_module.py +0 -0
  176. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/tool_module.py +0 -0
  177. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/trigger_handler.py +0 -0
  178. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/triggers/__init__.py +0 -0
  179. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  180. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  181. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  182. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/py.typed +0 -0
  183. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/__init__.py +0 -0
  184. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/base_strategy.py +0 -0
  185. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/communication/__init__.py +0 -0
  186. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  187. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/communication/default_communication.py +0 -0
  188. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/communication/exceptions.py +0 -0
  189. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/cost/__init__.py +0 -0
  190. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  191. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/cost/default_cost.py +0 -0
  192. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/cost/exceptions.py +0 -0
  193. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  194. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/filesystem/__init__.py +0 -0
  195. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  196. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  197. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  198. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  199. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/identity/__init__.py +0 -0
  200. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/identity/default_identity.py +0 -0
  201. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  202. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/__init__.py +0 -0
  203. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/default_registry.py +0 -0
  204. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/exceptions.py +0 -0
  205. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/grpc_registry.py +0 -0
  206. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/registry_models.py +0 -0
  207. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/registry/registry_strategy.py +0 -0
  208. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/setup/__init__.py +0 -0
  209. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/setup/default_setup.py +0 -0
  210. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/setup/exceptions.py +0 -0
  211. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  212. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  213. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/storage/__init__.py +0 -0
  214. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/storage/default_storage.py +0 -0
  215. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/storage/exceptions.py +0 -0
  216. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  217. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  218. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/task_manager/__init__.py +0 -0
  219. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
  220. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  221. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  222. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  223. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/user_profile/__init__.py +0 -0
  224. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  225. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/__init__.py +0 -0
  226. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/arg_parser.py +0 -0
  227. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/conditional_schema.py +0 -0
  228. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/development_mode_action.py +0 -0
  229. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/dynamic_schema.py +0 -0
  230. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/exceptions.py +0 -0
  231. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  232. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/package_discover.py +0 -0
  233. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/proto_utils.py +0 -0
  234. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin/utils/schema_splitter.py +0 -0
  235. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  236. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/src/digitalkin.egg-info/top_level.txt +0 -0
  237. {digitalkin-1.0.0.dev21 → digitalkin-1.0.0.dev23}/tests/test_exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.0.dev21
3
+ Version: 1.0.0.dev23
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: ag-ui-protocol>=0.1.18
456
- Requires-Dist: agentic-mesh-protocol==1.0.0a0
456
+ Requires-Dist: agentic-mesh-protocol==1.0.0a2
457
457
  Requires-Dist: anyio>=4.13.0
458
458
  Requires-Dist: grpcio-health-checking==1.81.0
459
459
  Requires-Dist: grpcio-reflection==1.81.0
@@ -28,7 +28,7 @@
28
28
 
29
29
  dependencies = [
30
30
  "ag-ui-protocol>=0.1.18",
31
- "agentic-mesh-protocol==1.0.0a0",
31
+ "agentic-mesh-protocol==1.0.0a2",
32
32
  "anyio>=4.13.0",
33
33
  "grpcio-health-checking==1.81.0",
34
34
  "grpcio-reflection==1.81.0",
@@ -37,7 +37,7 @@
37
37
  "pydantic-settings>=2.14.1",
38
38
  "redis[hiredis]>=7.4.0,<9",
39
39
  ]
40
- version = "1.0.0.dev21"
40
+ version = "1.0.0.dev23"
41
41
 
42
42
  [project.optional-dependencies]
43
43
  performance = [ "uvloop>=0.21" ]
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "1.0.0.dev21"
8
+ __version__ = "1.0.0.dev23"
@@ -13,6 +13,7 @@ from redis.exceptions import RedisError
13
13
  from digitalkin.core.exceptions import BackpressureTimeoutError
14
14
  from digitalkin.core.profiling.step_timer import StepTimer
15
15
  from digitalkin.core.profiling.task_profiler import TaskProfiler
16
+ from digitalkin.grpc_servers.exceptions import PermissionDeniedError
16
17
  from digitalkin.grpc_servers.interceptors.request_ids import RequestContext
17
18
  from digitalkin.logger import logger
18
19
  from digitalkin.models.grpc_servers.stream_error_codes import StreamErrorCode
@@ -226,6 +227,9 @@ class ModuleRunner:
226
227
  StreamErrorCode.REDIS_UNAVAILABLE.value,
227
228
  f"redis unavailable: {type(exc).__name__}: {exc}",
228
229
  )
230
+ except PermissionDeniedError as exc:
231
+ logger.warning("ModuleRunner: setup access denied: %s", exc, extra=log_extra)
232
+ await on_fatal(StreamErrorCode.SETUP_ACCESS_DENIED.value, str(exc))
229
233
  except Exception as exc:
230
234
  logger.exception("ModuleRunner: module job failed", extra=log_extra)
231
235
  await on_fatal(
@@ -7,6 +7,7 @@ import contextlib
7
7
  import json
8
8
  import random
9
9
  import time
10
+ import uuid
10
11
  from datetime import datetime, timezone
11
12
  from typing import TYPE_CHECKING, Any
12
13
 
@@ -158,6 +159,43 @@ class GatewayServicer:
158
159
  await self._m2m.stop()
159
160
  await self._registry.shutdown()
160
161
 
162
+ async def AssociateTask(
163
+ self,
164
+ request: Any,
165
+ context: grpc.aio.ServicerContext, # noqa: ARG002
166
+ ) -> Any:
167
+ """Mint a sub-task id linked to a running parent task.
168
+
169
+ Args:
170
+ request: AssociateTaskRequest proto.
171
+ context: gRPC service context.
172
+
173
+ Returns:
174
+ AssociateTaskResponse(task_id, parent_task_id); empty ``task_id`` on rejection.
175
+ """
176
+ parent_task_id = request.parent_task_id
177
+ err = GatewayValidator.validate_id(parent_task_id, "parent_task_id")
178
+ if err is not None:
179
+ logger.warning("AssociateTask rejected: %s", err)
180
+ return gateway_pb2.AssociateTaskResponse(task_id="", parent_task_id=parent_task_id)
181
+
182
+ child_task_id = str(uuid.uuid4())
183
+ ttl = get_gateway_settings().stream.redis_stream_initial_ttl
184
+ try:
185
+ await self._redis_client.sadd(f"task:{parent_task_id}:children", child_task_id)
186
+ await self._redis_client.expire(f"task:{parent_task_id}:children", ttl)
187
+ await self._redis_client.set(f"task:{child_task_id}:parent", parent_task_id, ex=ttl)
188
+ except RedisError:
189
+ logger.warning(
190
+ "[VALIDATE AT1] AssociateTask persist failed parent=%s → task_id=''",
191
+ parent_task_id,
192
+ exc_info=True,
193
+ ) # TODO(validate): remove after prod validation
194
+ return gateway_pb2.AssociateTaskResponse(task_id="", parent_task_id=parent_task_id)
195
+
196
+ logger.info("AssociateTask: parent=%s child=%s", parent_task_id, child_task_id)
197
+ return gateway_pb2.AssociateTaskResponse(task_id=child_task_id, parent_task_id=parent_task_id)
198
+
161
199
  async def StartStream( # noqa: PLR0911, PLR0915
162
200
  self,
163
201
  request: Any,
@@ -14,12 +14,13 @@ from agentic_mesh_protocol.module.v1 import (
14
14
  lifecycle_pb2,
15
15
  module_service_pb2_grpc,
16
16
  )
17
+ from agentic_mesh_protocol.user_profile.v1 import user_profile_pb2
17
18
  from google.protobuf import json_format, struct_pb2
18
19
 
19
20
  from digitalkin.core.job_manager.base_job_manager import BaseJobManager
20
21
  from digitalkin.core.job_manager.single_job_manager import SingleJobManager
21
22
  from digitalkin.core.task_manager.redis.redis_signal import SharedRedisListener
22
- from digitalkin.grpc_servers.exceptions import ServicerError
23
+ from digitalkin.grpc_servers.exceptions import PermissionDeniedError, ServicerError
23
24
  from digitalkin.logger import logger
24
25
  from digitalkin.models.module.module import ModuleCodeModel
25
26
  from digitalkin.models.module.setup_types import SetupModel
@@ -31,6 +32,7 @@ from digitalkin.services.registry import GrpcRegistry, RegistryStrategy
31
32
  from digitalkin.services.setup.default_setup import DefaultSetup
32
33
  from digitalkin.services.setup.grpc_setup import GrpcSetup
33
34
  from digitalkin.services.setup.setup_strategy import SetupStrategy, SetupVersionData
35
+ from digitalkin.services.user_profile import DefaultUserProfile, GrpcUserProfile, UserProfileStrategy
34
36
  from digitalkin.utils.arg_parser import ArgParser
35
37
  from digitalkin.utils.development_mode_action import DevelopmentModeMappingAction
36
38
 
@@ -40,6 +42,7 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
40
42
 
41
43
  args: Namespace
42
44
  setup: SetupStrategy
45
+ user_profile: UserProfileStrategy
43
46
  job_manager: BaseJobManager
44
47
  _registry_cache: RegistryStrategy | None
45
48
  _tool_cache_by_setup: dict[str, tuple[Any, float]]
@@ -82,6 +85,16 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
82
85
 
83
86
  logger.debug("ModuleServicer initialized with SingleJobManager")
84
87
  self.setup = GrpcSetup() if self.args.services_mode == ServicesMode.REMOTE else DefaultSetup()
88
+ # Access-control client gating the setup cache. Always built, always called (fail-closed).
89
+ if self.args.services_mode == ServicesMode.REMOTE:
90
+ up_cfg = self.module_class.services_config_params.get("user_profile") or {}
91
+ up_client_config = up_cfg.get("client_config")
92
+ if not up_client_config:
93
+ msg = "user_profile client_config is required for setup access control"
94
+ raise RuntimeError(msg)
95
+ self.user_profile = GrpcUserProfile("", "", "", up_client_config)
96
+ else:
97
+ self.user_profile = DefaultUserProfile("", "", "")
85
98
  self._setup_cache: dict[str, tuple[float, SetupVersionData]] = {}
86
99
  self._setup_inflight: dict[str, asyncio.Future[SetupVersionData]] = {}
87
100
 
@@ -97,6 +110,11 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
97
110
  await self.setup.close_channel()
98
111
  except Exception:
99
112
  logger.exception("Error closing GrpcSetup channel")
113
+ if isinstance(self.user_profile, GrpcUserProfile):
114
+ try:
115
+ await self.user_profile.close_channel()
116
+ except Exception:
117
+ logger.exception("Error closing GrpcUserProfile channel")
100
118
  # M8: close the Redis connection pools (were leaked on every server stop).
101
119
  logger.info("[VALIDATE M8] closing module servicer Redis pools") # TODO(validate): remove after prod validation
102
120
  await self._redis_client.close()
@@ -245,6 +263,19 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
245
263
  del self._setup_cache[oldest_key]
246
264
  self._setup_cache[setup_id] = (time.monotonic(), version_data)
247
265
 
266
+ async def _check_setup_access(self, setup_id: str) -> None:
267
+ """Block if the caller may not access the setup (RESOURCE_TYPE_SETUP).
268
+
269
+ Args:
270
+ setup_id: The setup identifier being resolved.
271
+
272
+ Raises:
273
+ PermissionDeniedError: If access to the setup is denied.
274
+ """
275
+ if not await self.user_profile.check_resource_access(user_profile_pb2.RESOURCE_TYPE_SETUP, setup_id):
276
+ msg = f"access denied to setup {setup_id}"
277
+ raise PermissionDeniedError(msg)
278
+
248
279
  async def resolve_setup(self, setup_id: str, mission_id: str) -> SetupVersionData:
249
280
  """Return setup version data from cache or remote service.
250
281
 
@@ -257,7 +288,9 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
257
288
 
258
289
  Raises:
259
290
  LookupError: No setup data found for setup_id.
291
+ PermissionDeniedError: If the caller may not access this setup.
260
292
  """
293
+ await self._check_setup_access(setup_id)
261
294
  # Fast path: cache hit within TTL
262
295
  if (cached := self._setup_cache.get(setup_id)) is not None:
263
296
  if time.monotonic() - cached[0] < get_module_servicer_settings().setup_cache_ttl:
@@ -326,6 +359,12 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
326
359
  extra={"mission_id": request.mission_id},
327
360
  )
328
361
  setup_version = request.setup_version
362
+ if not await self.user_profile.check_resource_access(
363
+ user_profile_pb2.RESOURCE_TYPE_SETUP, setup_version.setup_id
364
+ ):
365
+ context.set_code(grpc.StatusCode.PERMISSION_DENIED)
366
+ context.set_details(f"access denied to setup {setup_version.setup_id}")
367
+ return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
329
368
  # Invalidate cached setup so concurrent/subsequent starts refetch the reconfigured version
330
369
  self._setup_cache.pop(setup_version.setup_id, None)
331
370
  config_setup_data = self.module_class.create_config_setup_model(json_format.MessageToDict(request.content))
@@ -23,3 +23,4 @@ class StreamErrorCode(str, Enum):
23
23
  MODULE_RUNTIME_ERROR = "MODULE_RUNTIME_ERROR"
24
24
  INPUT_VALIDATION_ERROR = "INPUT_VALIDATION_ERROR"
25
25
  BACKPRESSURE_TIMEOUT = "BACKPRESSURE_TIMEOUT"
26
+ SETUP_ACCESS_DENIED = "SETUP_ACCESS_DENIED"
@@ -17,6 +17,7 @@ from digitalkin.services.cost.cost_strategy import CostStrategy
17
17
  from digitalkin.services.filesystem.filesystem_strategy import FilesystemStrategy
18
18
  from digitalkin.services.identity.identity_strategy import IdentityStrategy
19
19
  from digitalkin.services.registry.registry_strategy import RegistryStrategy
20
+ from digitalkin.services.secret.secret_strategy import SecretStrategy
20
21
  from digitalkin.services.storage.storage_strategy import StorageStrategy
21
22
  from digitalkin.services.task_manager.task_manager_strategy import TaskManagerStrategy
22
23
  from digitalkin.services.user_profile.user_profile_strategy import UserProfileStrategy
@@ -95,6 +96,7 @@ class ModuleContext:
95
96
  filesystem: FilesystemStrategy
96
97
  identity: IdentityStrategy
97
98
  registry: RegistryStrategy
99
+ secret: SecretStrategy
98
100
  storage: StorageStrategy
99
101
  task_manager: TaskManagerStrategy | None
100
102
  user_profile: UserProfileStrategy
@@ -115,6 +117,7 @@ class ModuleContext:
115
117
  filesystem: FilesystemStrategy,
116
118
  identity: IdentityStrategy,
117
119
  registry: RegistryStrategy,
120
+ secret: SecretStrategy,
118
121
  storage: StorageStrategy,
119
122
  user_profile: UserProfileStrategy,
120
123
  session: dict[str, Any],
@@ -135,6 +138,7 @@ class ModuleContext:
135
138
  filesystem: FilesystemStrategy.
136
139
  identity: IdentityStrategy.
137
140
  registry: RegistryStrategy.
141
+ secret: SecretStrategy.
138
142
  storage: StorageStrategy.
139
143
  user_profile: UserProfileStrategy.
140
144
  task_manager: Optional, injected by SingleJobManager (RedisTaskManager).
@@ -153,6 +157,7 @@ class ModuleContext:
153
157
  self.filesystem = filesystem
154
158
  self.identity = identity
155
159
  self.registry = registry
160
+ self.secret = secret
156
161
  self.storage = storage
157
162
  self.task_manager = task_manager
158
163
  self.user_profile = user_profile
@@ -374,6 +379,7 @@ class ModuleContext:
374
379
  ("registry", self.registry),
375
380
  ("filesystem", self.filesystem),
376
381
  ("user_profile", self.user_profile),
382
+ ("secret", self.secret),
377
383
  ("identity", self.identity),
378
384
  )
379
385
  for name, service in owned:
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import time
7
- import uuid
8
7
  from typing import TYPE_CHECKING, Any
9
8
 
10
9
  import grpc.aio
@@ -16,6 +15,7 @@ from agentic_mesh_protocol.module.v1 import (
16
15
  from google.protobuf import json_format, struct_pb2
17
16
 
18
17
  from digitalkin.core.profiling.step_timer import StepTimer
18
+ from digitalkin.grpc_servers.interceptors.request_ids import RequestContext
19
19
  from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
20
20
  from digitalkin.grpc_servers.utils.validators import GatewayValidator
21
21
  from digitalkin.logger import logger
@@ -315,8 +315,7 @@ class GrpcCommunication(CommunicationStrategy, GrpcClientWrapper):
315
315
  "target_key": target_key,
316
316
  }
317
317
 
318
- task_id = str(uuid.uuid4())
319
- log_extra["task_id"] = task_id
318
+ task_id = ""
320
319
  breaker = m2m.breaker_for(target_key)
321
320
 
322
321
  last_mark = "init"
@@ -342,6 +341,38 @@ class GrpcCommunication(CommunicationStrategy, GrpcClientWrapper):
342
341
  timer.mark("acquire_slot")
343
342
  last_mark = "acquire_slot"
344
343
 
344
+ self._get_or_create_channel(module_address, module_port)
345
+ timer.mark("channel_create")
346
+ last_mark = "channel_create"
347
+ stub = self._get_or_create_stub(gateway_service_pb2_grpc.GatewayServiceStub)
348
+ timer.mark("stub_create")
349
+ last_mark = "stub_create"
350
+
351
+ # The gateway mints the sub-task id and links it to the running parent task.
352
+ try:
353
+ assoc = await stub.AssociateTask(
354
+ gateway_pb2.AssociateTaskRequest(
355
+ parent_task_id=RequestContext.current().get("task_id", ""),
356
+ ),
357
+ )
358
+ except grpc.aio.AioRpcError as exc:
359
+ breaker.record_failure()
360
+ logger.warning(
361
+ "[m2m] AssociateTask failed: [%s] %s",
362
+ exc.code().name,
363
+ exc.details() or "",
364
+ extra=log_extra,
365
+ )
366
+ raise
367
+ task_id = assoc.task_id
368
+ if not task_id:
369
+ breaker.record_failure()
370
+ msg = f"target {target_key} returned no task_id from AssociateTask"
371
+ raise RuntimeError(msg) # noqa: TRY301
372
+ log_extra["task_id"] = task_id
373
+ timer.mark("associate_task")
374
+ last_mark = "associate_task"
375
+
345
376
  output_queue: asyncio.Queue[struct_pb2.Struct | None] = asyncio.Queue(
346
377
  maxsize=m2m_settings.call_queue_maxsize,
347
378
  )
@@ -361,13 +392,6 @@ class GrpcCommunication(CommunicationStrategy, GrpcClientWrapper):
361
392
  timer.mark("register")
362
393
  last_mark = "register"
363
394
 
364
- self._get_or_create_channel(module_address, module_port)
365
- timer.mark("channel_create")
366
- last_mark = "channel_create"
367
- stub = self._get_or_create_stub(gateway_service_pb2_grpc.GatewayServiceStub)
368
- timer.mark("stub_create")
369
- last_mark = "stub_create"
370
-
371
395
  try: # noqa: PLW0717
372
396
  grpc_metadata: list[tuple[str, str]] = []
373
397
  if metadata:
@@ -467,7 +491,7 @@ class GrpcCommunication(CommunicationStrategy, GrpcClientWrapper):
467
491
  cancelled = True
468
492
  raise
469
493
  finally:
470
- if cancelled and stub is not None:
494
+ if cancelled and stub is not None and task_id:
471
495
  sig_t0 = time.perf_counter_ns()
472
496
  sig_failure = ""
473
497
  try:
@@ -0,0 +1,13 @@
1
+ """Secret service package."""
2
+
3
+ from digitalkin.services.secret.default_secret import DefaultSecret
4
+ from digitalkin.services.secret.exceptions import SecretServiceError
5
+ from digitalkin.services.secret.grpc_secret import GrpcSecret
6
+ from digitalkin.services.secret.secret_strategy import SecretStrategy
7
+
8
+ __all__ = [
9
+ "DefaultSecret",
10
+ "GrpcSecret",
11
+ "SecretServiceError",
12
+ "SecretStrategy",
13
+ ]
@@ -0,0 +1,45 @@
1
+ """Default secret implementation."""
2
+
3
+ from typing import Any
4
+
5
+ from digitalkin.logger import logger
6
+ from digitalkin.services.secret.secret_strategy import SecretStrategy
7
+
8
+
9
+ class DefaultSecret(SecretStrategy):
10
+ """Default secret strategy with in-memory storage."""
11
+
12
+ def __init__(
13
+ self,
14
+ mission_id: str,
15
+ setup_id: str,
16
+ setup_version_id: str,
17
+ ) -> None:
18
+ """Initialize the strategy.
19
+
20
+ Args:
21
+ mission_id: The ID of the mission this strategy is associated with
22
+ setup_id: The ID of the setup
23
+ setup_version_id: The ID of the setup version
24
+ """
25
+ super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
26
+ self.db: dict[str, dict[str, Any]] = {}
27
+
28
+ async def get_secret(self) -> dict[str, Any] | None:
29
+ """Get the secret for this setup from in-memory storage.
30
+
31
+ Returns:
32
+ Secret values, or None if not found.
33
+ """
34
+ if self.setup_id not in self.db:
35
+ logger.warning("No secret found for setup_id: %s", self.setup_id)
36
+ return None
37
+ return self.db[self.setup_id]
38
+
39
+ def add_secret(self, secret_data: dict[str, Any]) -> None:
40
+ """Add a secret to the in-memory database (helper for testing).
41
+
42
+ Args:
43
+ secret_data: Dictionary containing secret values.
44
+ """
45
+ self.db[self.setup_id] = secret_data
@@ -0,0 +1,5 @@
1
+ """Exceptions for the secret service."""
2
+
3
+
4
+ class SecretServiceError(Exception):
5
+ """Base exception for Secret service errors."""
@@ -0,0 +1,63 @@
1
+ """Digital Kin Secret Service gRPC Client (wraps UserProfileService.GetSetupSecret)."""
2
+
3
+ from typing import Any
4
+
5
+ from agentic_mesh_protocol.user_profile.v1 import (
6
+ user_profile_pb2,
7
+ user_profile_service_pb2_grpc,
8
+ )
9
+
10
+ from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
11
+ from digitalkin.grpc_servers.utils.grpc_error_handler import GrpcErrorHandlerMixin
12
+ from digitalkin.logger import logger
13
+ from digitalkin.models.grpc_servers.models import ClientConfig
14
+ from digitalkin.services.secret.exceptions import SecretServiceError
15
+ from digitalkin.services.secret.secret_strategy import SecretStrategy
16
+ from digitalkin.utils.proto_utils import ProtoUtils
17
+
18
+
19
+ class GrpcSecret(SecretStrategy, GrpcClientWrapper, GrpcErrorHandlerMixin):
20
+ """gRPC client for setup secrets (backed by the UserProfileService)."""
21
+
22
+ service_name: str = "UserProfileService"
23
+
24
+ def __init__(
25
+ self,
26
+ mission_id: str,
27
+ setup_id: str,
28
+ setup_version_id: str,
29
+ client_config: ClientConfig,
30
+ ) -> None:
31
+ """Initialize the secret service.
32
+
33
+ Args:
34
+ mission_id: The ID of the mission this strategy is associated with
35
+ setup_id: The ID of the setup
36
+ setup_version_id: The ID of the setup version
37
+ client_config: Client configuration for gRPC connection
38
+ """
39
+ super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
40
+ self._init_channel(client_config)
41
+ self.stub = self._get_or_create_stub(user_profile_service_pb2_grpc.UserProfileServiceStub)
42
+ logger.debug("Channel client 'Secret' initialized successfully")
43
+
44
+ async def close(self) -> None:
45
+ """Release this instance's pooled gRPC channel ref."""
46
+ await self.close_channel()
47
+
48
+ async def get_secret(self) -> dict[str, Any] | None:
49
+ """Resolve the secret object attached to this setup.
50
+
51
+ Returns:
52
+ The secret values, or None if not found.
53
+
54
+ Raises:
55
+ SecretServiceError: If the gRPC operation fails.
56
+ """
57
+ async with self.handle_grpc_errors("GetSetupSecret", SecretServiceError):
58
+ request = user_profile_pb2.GetSetupSecretRequest(setup_id=self.setup_id, mission_id=self.mission_id)
59
+ response = await self.exec_grpc_query("GetSetupSecret", request)
60
+ if not response.success:
61
+ logger.warning("No secret found for setup_id: %s", self.setup_id)
62
+ return None
63
+ return ProtoUtils.proto_to_dict(response.secret, with_defaults=True)
@@ -0,0 +1,21 @@
1
+ """This module contains the abstract base class for Secret strategies."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any
5
+
6
+ from digitalkin.services.base_strategy import BaseStrategy
7
+
8
+
9
+ class SecretStrategy(BaseStrategy, ABC):
10
+ """Abstract base class for Secret strategies."""
11
+
12
+ @abstractmethod
13
+ async def get_secret(self) -> dict[str, Any] | None:
14
+ """Resolve the secret object attached to this setup.
15
+
16
+ Returns:
17
+ The secret values (matching the module's secret_schema), or None if not found.
18
+
19
+ Raises:
20
+ SecretServiceError: If the service call fails.
21
+ """
@@ -10,6 +10,7 @@ from digitalkin.services.cost import CostStrategy, DefaultCost, GrpcCost
10
10
  from digitalkin.services.filesystem import DefaultFilesystem, FilesystemStrategy, GrpcFilesystem
11
11
  from digitalkin.services.identity import DefaultIdentity, IdentityStrategy
12
12
  from digitalkin.services.registry import DefaultRegistry, GrpcRegistry, RegistryStrategy
13
+ from digitalkin.services.secret import DefaultSecret, GrpcSecret, SecretStrategy
13
14
  from digitalkin.services.services_models import ServicesStrategy
14
15
  from digitalkin.services.storage import DefaultStorage, GrpcStorage, StorageStrategy
15
16
  from digitalkin.services.user_profile import DefaultUserProfile, GrpcUserProfile, UserProfileStrategy
@@ -36,6 +37,7 @@ class ServicesConfig(BaseModel):
36
37
  "identity",
37
38
  "communication",
38
39
  "user_profile",
40
+ "secret",
39
41
  }
40
42
 
41
43
  def __init__(
@@ -67,6 +69,7 @@ class ServicesConfig(BaseModel):
67
69
  "identity": ServicesStrategy(local=DefaultIdentity, remote=DefaultIdentity),
68
70
  "communication": ServicesStrategy(local=DefaultCommunication, remote=GrpcCommunication),
69
71
  "user_profile": ServicesStrategy(local=DefaultUserProfile, remote=GrpcUserProfile),
72
+ "secret": ServicesStrategy(local=DefaultSecret, remote=GrpcSecret),
70
73
  }
71
74
 
72
75
  # Apply strategy overrides
@@ -75,6 +78,12 @@ class ServicesConfig(BaseModel):
75
78
  self._strategies[name] = override if override is not None else defaults[name]
76
79
  self._configs[name] = services_config_params.get(name) or {}
77
80
 
81
+ # The secret service is backed by the UserProfileService — reuse the
82
+ # user_profile client_config (same host/port) when no dedicated secret
83
+ # config is registered, so GrpcSecret can build its channel.
84
+ if not self._configs.get("secret"):
85
+ self._configs["secret"] = self._configs.get("user_profile") or {}
86
+
78
87
  @classmethod
79
88
  def valid_strategy_names(cls) -> set[str]:
80
89
  """Get the list of valid strategy names.
@@ -162,6 +171,11 @@ class ServicesConfig(BaseModel):
162
171
  """The user_profile service strategy class for the current mode."""
163
172
  return self._strategies["user_profile"][self.mode.value]
164
173
 
174
+ @property
175
+ def secret(self) -> type[SecretStrategy]:
176
+ """The secret service strategy class for the current mode."""
177
+ return self._strategies["secret"][self.mode.value]
178
+
165
179
  def update_mode(self, mode: ServicesMode) -> None:
166
180
  """Update the strategy mode.
167
181
 
@@ -11,6 +11,7 @@ from digitalkin.services.cost import CostStrategy
11
11
  from digitalkin.services.filesystem import FilesystemStrategy
12
12
  from digitalkin.services.identity import IdentityStrategy
13
13
  from digitalkin.services.registry import RegistryStrategy
14
+ from digitalkin.services.secret import SecretStrategy
14
15
  from digitalkin.services.storage import StorageStrategy
15
16
  from digitalkin.services.task_manager.task_manager_strategy import TaskManagerStrategy
16
17
  from digitalkin.services.user_profile import UserProfileStrategy
@@ -23,6 +24,7 @@ T = TypeVar(
23
24
  | FilesystemStrategy
24
25
  | IdentityStrategy
25
26
  | RegistryStrategy
27
+ | SecretStrategy
26
28
  | StorageStrategy
27
29
  | UserProfileStrategy
28
30
  | TaskManagerStrategy,
@@ -38,6 +38,18 @@ class DefaultUserProfile(UserProfileStrategy):
38
38
  logger.debug("Retrieved user profile for mission_id: %s", self.mission_id)
39
39
  return self.db[self.mission_id]
40
40
 
41
+ async def check_resource_access(self, resource_type: int, resource_id: str) -> bool: # noqa: ARG002, PLR6301
42
+ """Local strategy: grant access (no access backend in local mode).
43
+
44
+ Args:
45
+ resource_type: The ResourceType enum value.
46
+ resource_id: The resource identifier.
47
+
48
+ Returns:
49
+ True.
50
+ """
51
+ return True
52
+
41
53
  def add_user_profile(self, user_profile_data: dict[str, Any]) -> None:
42
54
  """Add a user profile to the in-memory database (helper for testing).
43
55
 
@@ -1,6 +1,6 @@
1
1
  """Digital Kin UserProfile Service gRPC Client."""
2
2
 
3
- from typing import Any
3
+ from typing import Any, cast
4
4
 
5
5
  from agentic_mesh_protocol.user_profile.v1 import (
6
6
  user_profile_pb2,
@@ -69,3 +69,24 @@ class GrpcUserProfile(UserProfileStrategy, GrpcClientWrapper, GrpcErrorHandlerMi
69
69
 
70
70
  logger.debug("Retrieved user profile for mission_id: %s", self.mission_id)
71
71
  return user_profile_dict
72
+
73
+ async def check_resource_access(self, resource_type: int, resource_id: str) -> bool:
74
+ """Check whether the caller may access a resource (e.g. a setup).
75
+
76
+ Args:
77
+ resource_type: The ResourceType enum value (e.g. RESOURCE_TYPE_SETUP).
78
+ resource_id: The resource identifier (e.g. the setup_id).
79
+
80
+ Returns:
81
+ True if access is granted, False otherwise.
82
+
83
+ Raises:
84
+ UserProfileServiceError: If the gRPC operation fails.
85
+ """
86
+ async with self.handle_grpc_errors("CheckResourceAccess", UserProfileServiceError):
87
+ request = user_profile_pb2.CheckResourceAccessRequest(
88
+ resource_type=cast("user_profile_pb2.ResourceType", resource_type),
89
+ resource_id=resource_id,
90
+ )
91
+ response = await self.exec_grpc_query("CheckResourceAccess", request)
92
+ return response.allowed
@@ -19,3 +19,18 @@ class UserProfileStrategy(BaseStrategy, ABC):
19
19
  Raises:
20
20
  UserProfileServiceError: If the service call fails (not for missing profiles).
21
21
  """
22
+
23
+ @abstractmethod
24
+ async def check_resource_access(self, resource_type: int, resource_id: str) -> bool:
25
+ """Check whether the caller may access a resource.
26
+
27
+ Args:
28
+ resource_type: The ResourceType enum value (e.g. RESOURCE_TYPE_SETUP).
29
+ resource_id: The resource identifier (e.g. the setup_id).
30
+
31
+ Returns:
32
+ True if access is granted, False otherwise.
33
+
34
+ Raises:
35
+ UserProfileServiceError: If the service call fails.
36
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.0.dev21
3
+ Version: 1.0.0.dev23
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: ag-ui-protocol>=0.1.18
456
- Requires-Dist: agentic-mesh-protocol==1.0.0a0
456
+ Requires-Dist: agentic-mesh-protocol==1.0.0a2
457
457
  Requires-Dist: anyio>=4.13.0
458
458
  Requires-Dist: grpcio-health-checking==1.81.0
459
459
  Requires-Dist: grpcio-reflection==1.81.0