digitalkin 1.0.3.dev1__tar.gz → 1.0.4.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.
Files changed (263) hide show
  1. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/PKG-INFO +2 -2
  2. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/pyproject.toml +45 -45
  3. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/action.py +13 -0
  5. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/base.py +5 -1
  6. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +66 -33
  7. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +1 -1
  8. digitalkin-1.0.4.dev0/src/digitalkin/community/agno/toolkits/registry/services/action.py +151 -0
  9. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +9 -5
  10. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +1 -1
  11. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/profiling/task_profiler.py +3 -3
  12. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/base_task_manager.py +1 -1
  13. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/local_task_manager.py +1 -1
  14. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/module_runner.py +6 -6
  15. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/proto_streams.py +1 -1
  16. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/redis_client.py +1 -1
  17. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/redis_signal.py +6 -6
  18. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/redis_state.py +1 -1
  19. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/remote_task_manager.py +1 -1
  20. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/task_executor.py +3 -3
  21. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/_base_server.py +11 -11
  22. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/gateway_servicer.py +21 -21
  23. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/interceptors/permission.py +9 -9
  24. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/interceptors/request_ids.py +1 -1
  25. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/m2m_call_registry.py +2 -2
  26. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/module_server.py +6 -6
  27. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/module_servicer.py +1 -1
  28. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/stream_registry.py +3 -3
  29. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +1 -1
  30. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +1 -1
  31. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +2 -2
  32. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/validators.py +1 -1
  33. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/logger.py +1 -1
  34. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/agui_mixin.py +1 -1
  35. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/models.py +2 -2
  36. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/__init__.py +8 -0
  37. digitalkin-1.0.4.dev0/src/digitalkin/models/module/loaded_tools.py +140 -0
  38. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/module_context.py +90 -6
  39. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/setup_types.py +1 -1
  40. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/tool_cache.py +70 -10
  41. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/services/registry.py +3 -0
  42. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/utils/channel.py +1 -1
  43. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/_base_module.py +16 -9
  44. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/trigger_handler.py +1 -1
  45. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +2 -2
  46. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +3 -3
  47. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +2 -2
  48. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/communication/communication_strategy.py +1 -1
  49. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/communication/default_communication.py +5 -5
  50. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/communication/exceptions.py +2 -2
  51. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/communication/grpc_communication.py +6 -6
  52. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +13 -13
  53. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/identity/default_identity.py +1 -1
  54. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/default_registry.py +5 -2
  55. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/grpc_registry.py +3 -2
  56. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/registry_strategy.py +2 -2
  57. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/setup/default_setup.py +32 -6
  58. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/setup/grpc_setup.py +54 -12
  59. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/setup/setup_strategy.py +23 -6
  60. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/storage/default_storage.py +1 -1
  61. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/task_manager/default_task_manager.py +4 -4
  62. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/user_profile/default_user_profile.py +1 -1
  63. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/arg_parser.py +6 -6
  64. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/development_mode_action.py +3 -3
  65. digitalkin-1.0.4.dev0/src/digitalkin/utils/json_structure.py +363 -0
  66. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/llm_ready_schema.py +1 -1
  67. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/package_discover.py +3 -3
  68. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/schema_splitter.py +4 -4
  69. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin.egg-info/PKG-INFO +2 -2
  70. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin.egg-info/SOURCES.txt +2 -0
  71. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin.egg-info/requires.txt +1 -1
  72. digitalkin-1.0.3.dev1/src/digitalkin/community/agno/toolkits/registry/services/action.py +0 -92
  73. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/LICENSE +0 -0
  74. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/README.md +0 -0
  75. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/__init__.py +0 -0
  76. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/mock/__init__.py +0 -0
  77. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
  78. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  79. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/server_async_insecure.py +0 -0
  80. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/server_async_secure.py +0 -0
  81. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/server_sync_insecure.py +0 -0
  82. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/base_server/server_sync_secure.py +0 -0
  83. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/__init__.py +0 -0
  84. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/echo_module.py +0 -0
  85. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/models/__init__.py +0 -0
  86. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/models/input.py +0 -0
  87. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/models/output.py +0 -0
  88. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/models/secret.py +0 -0
  89. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/models/setup.py +0 -0
  90. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/server.py +0 -0
  91. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/triggers/__init__.py +0 -0
  92. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/bench_module/triggers/message_trigger.py +0 -0
  93. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/__init__.py +0 -0
  94. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/archetype_with_tools_module.py +0 -0
  95. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/cpu_intensive_module.py +0 -0
  96. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/dynamic_setup_module.py +0 -0
  97. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/minimal_llm_module.py +0 -0
  98. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/modules/text_transform_module.py +0 -0
  99. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  100. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  101. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  102. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  103. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  104. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/monitoring/tests/test_metrics.py +0 -0
  105. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/client.py +0 -0
  106. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/echo_module.py +0 -0
  107. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/models/__init__.py +0 -0
  108. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/models/input.py +0 -0
  109. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/models/output.py +0 -0
  110. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/models/secret.py +0 -0
  111. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/models/setup.py +0 -0
  112. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/server.py +0 -0
  113. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/triggers/__init__.py +0 -0
  114. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/redis_demo/triggers/message_trigger.py +0 -0
  115. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/services/filesystem_module.py +0 -0
  116. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/examples/services/storage_module.py +0 -0
  117. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/setup.cfg +0 -0
  118. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/__init__.py +0 -0
  119. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/__init__.py +0 -0
  120. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/__init__.py +0 -0
  121. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/agno_adapter.py +0 -0
  122. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/agui_tools.py +0 -0
  123. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/hitl.py +0 -0
  124. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/models.py +0 -0
  125. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/module_toolkit.py +0 -0
  126. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/__init__.py +0 -0
  127. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/base.py +0 -0
  128. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
  129. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/defaults.py +0 -0
  130. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
  131. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
  132. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
  133. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
  134. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
  135. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
  136. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
  137. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
  138. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
  139. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
  140. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/__init__.py +0 -0
  141. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/common/__init__.py +0 -0
  142. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/common/factories.py +0 -0
  143. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/exceptions.py +0 -0
  144. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
  145. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  146. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/profiling/__init__.py +0 -0
  147. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/profiling/step_timer.py +0 -0
  148. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/resilience/__init__.py +0 -0
  149. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  150. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  151. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
  152. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  153. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  154. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/core/task_manager/task_session.py +0 -0
  155. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/exceptions.py +0 -0
  156. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
  157. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  158. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  159. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  160. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  161. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  162. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/__init__.py +0 -0
  163. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
  164. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
  165. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  166. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  167. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
  168. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
  169. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/__init__.py +0 -0
  170. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/core/__init__.py +0 -0
  171. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
  172. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/core/redis.py +0 -0
  173. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
  174. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/events/__init__.py +0 -0
  175. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/events/agent_events.py +0 -0
  176. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  177. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  178. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  179. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
  180. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
  181. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/ag_ui.py +0 -0
  182. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/base_types.py +0 -0
  183. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/module.py +0 -0
  184. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/module_types.py +0 -0
  185. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/request_metadata.py +0 -0
  186. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/select_schema.py +0 -0
  187. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/tool_reference.py +0 -0
  188. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/module/utility.py +0 -0
  189. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/services/__init__.py +0 -0
  190. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/services/cost.py +0 -0
  191. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/services/services.py +0 -0
  192. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/services/storage.py +0 -0
  193. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/__init__.py +0 -0
  194. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/gateway.py +0 -0
  195. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/grpc_client.py +0 -0
  196. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/log.py +0 -0
  197. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/module.py +0 -0
  198. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/profiling.py +0 -0
  199. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/queue.py +0 -0
  200. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/redis.py +0 -0
  201. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/registry.py +0 -0
  202. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/resilience.py +0 -0
  203. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/server/__init__.py +0 -0
  204. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/server/channel.py +0 -0
  205. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/server/grpc.py +0 -0
  206. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/server/server.py +0 -0
  207. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/server/servicer.py +0 -0
  208. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/task_manager.py +0 -0
  209. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  210. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/utils/__init__.py +0 -0
  211. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  212. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/__init__.py +0 -0
  213. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/archetype_module.py +0 -0
  214. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/tool_module.py +0 -0
  215. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/modules/triggers/__init__.py +0 -0
  216. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/py.typed +0 -0
  217. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/__init__.py +0 -0
  218. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/base_strategy.py +0 -0
  219. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/communication/__init__.py +0 -0
  220. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
  221. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  222. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
  223. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/cost/exceptions.py +0 -0
  224. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  225. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
  226. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  227. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  228. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  229. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
  230. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  231. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
  232. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/exceptions.py +0 -0
  233. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/registry/registry_models.py +0 -0
  234. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/secret/__init__.py +0 -0
  235. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/secret/default_secret.py +0 -0
  236. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/secret/exceptions.py +0 -0
  237. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/secret/grpc_secret.py +0 -0
  238. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/secret/secret_strategy.py +0 -0
  239. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/services_config.py +0 -0
  240. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/services_models.py +0 -0
  241. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
  242. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/setup/exceptions.py +0 -0
  243. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
  244. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/storage/exceptions.py +0 -0
  245. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  246. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  247. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/task_manager/__init__.py +0 -0
  248. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  249. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  250. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  251. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/user_profile/__init__.py +0 -0
  252. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  253. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  254. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  255. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/__init__.py +0 -0
  256. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/conditional_schema.py +0 -0
  257. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/dynamic_schema.py +0 -0
  258. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/exceptions.py +0 -0
  259. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/proto_utils.py +0 -0
  260. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin/utils/setup_content_validator.py +0 -0
  261. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  262. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/src/digitalkin.egg-info/top_level.txt +0 -0
  263. {digitalkin-1.0.3.dev1 → digitalkin-1.0.4.dev0}/tests/test_exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.3.dev1
3
+ Version: 1.0.4.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: ag-ui-protocol==0.1.21.dev1787220377
456
- Requires-Dist: agentic-mesh-protocol==1.0.1
456
+ Requires-Dist: agentic-mesh-protocol==1.0.2.dev1
457
457
  Requires-Dist: agno<3,>=2.8.0
458
458
  Requires-Dist: anyio>=4.13.0
459
459
  Requires-Dist: grpcio-health-checking==1.82.1
@@ -31,7 +31,7 @@
31
31
  # which is how a nested run's output is attributed to its author. Pinned exactly
32
32
  # because it is a dated prerelease; move to >=0.1.21 once that ships stable.
33
33
  "ag-ui-protocol==0.1.21.dev1787220377",
34
- "agentic-mesh-protocol==1.0.1",
34
+ "agentic-mesh-protocol==1.0.2.dev1",
35
35
  "agno>=2.8.0,<3",
36
36
  "anyio>=4.13.0",
37
37
  "grpcio-health-checking==1.82.1",
@@ -41,7 +41,7 @@
41
41
  "pydantic>=2.12.4",
42
42
  "redis[hiredis]>=7.4.0,<9",
43
43
  ]
44
- version = "1.0.3.dev1"
44
+ version = "1.0.4.dev0"
45
45
 
46
46
  [project.optional-dependencies]
47
47
  agno = [ "agno>=2.6" ]
@@ -208,15 +208,15 @@
208
208
  ]
209
209
 
210
210
  ignore = [
211
- "ANN401", # Allow typing.Any — gRPC stubs, callbacks, and dynamic APIs require it
212
- "COM812", # Disable because of formatter incompatibility
213
- "DOC502", # Allow extraneous-exception in docstring
214
- "F401", # Allow unused imports — used for availability checks
215
- "N802", # Allow PascalCase methods — gRPC servicer convention
216
- "PLC0415", # Allow lazy imports — needed to break circular dependencies
217
- "PLW3201", # Allow __get_pydantic_core_schema__ — Pydantic dunder hook
218
- "S105", # Hardcoded-password
219
- "S403", # Allow pickle import
211
+ "any-type", # Allow typing.Any — gRPC stubs, callbacks, and dynamic APIs require it
212
+ "missing-trailing-comma", # Disable because of formatter incompatibility
213
+ "docstring-extraneous-exception", # Allow extraneous-exception in docstring
214
+ "unused-import", # Allow unused imports — used for availability checks
215
+ "invalid-function-name", # Allow PascalCase methods — gRPC servicer convention
216
+ "import-outside-top-level", # Allow lazy imports — needed to break circular dependencies
217
+ "bad-dunder-method-name", # Allow __get_pydantic_core_schema__ — Pydantic dunder hook
218
+ "hardcoded-password-string", # Hardcoded-password
219
+ "suspicious-pickle-import", # Allow pickle import
220
220
  ]
221
221
 
222
222
  fixable = [ "ALL" ]
@@ -226,40 +226,40 @@
226
226
 
227
227
  [tool.ruff.lint.per-file-ignores]
228
228
  "tests/**/*.py" = [
229
- "ANN001",
230
- "ANN002",
231
- "ANN003",
232
- "ANN201",
233
- "ANN401",
234
- "ARG001",
235
- "ARG002",
236
- "C901",
237
- "D100",
238
- "D101",
239
- "D102",
240
- "D103",
241
- "D107",
242
- "D417",
243
- "DOC201",
244
- "DOC501",
245
- "E501",
246
- "ERA001",
247
- "FBT001",
248
- "FBT002",
249
- "G004",
250
- "N802",
251
- "PERF203",
252
- "PLC2701",
253
- "PLR0911",
254
- "PLR0912",
255
- "PLR0914",
256
- "PLR0915",
257
- "PLR1702",
258
- "PLR2004",
259
- "PLR6301",
260
- "S101",
261
- "SLF001",
262
- "TRY002",
229
+ "missing-type-function-argument",
230
+ "missing-type-args",
231
+ "missing-type-kwargs",
232
+ "missing-return-type-undocumented-public-function",
233
+ "any-type",
234
+ "unused-function-argument",
235
+ "unused-method-argument",
236
+ "complex-structure",
237
+ "undocumented-public-module",
238
+ "undocumented-public-class",
239
+ "undocumented-public-method",
240
+ "undocumented-public-function",
241
+ "undocumented-public-init",
242
+ "undocumented-param",
243
+ "docstring-missing-returns",
244
+ "docstring-missing-exception",
245
+ "line-too-long",
246
+ "commented-out-code",
247
+ "boolean-type-hint-positional-argument",
248
+ "boolean-default-value-positional-argument",
249
+ "logging-f-string",
250
+ "invalid-function-name",
251
+ "try-except-in-loop",
252
+ "import-private-name",
253
+ "too-many-return-statements",
254
+ "too-many-branches",
255
+ "too-many-locals",
256
+ "too-many-statements",
257
+ "too-many-nested-blocks",
258
+ "magic-value-comparison",
259
+ "no-self-use",
260
+ "assert",
261
+ "private-member-access",
262
+ "raise-vanilla-class",
263
263
  ]
264
264
 
265
265
  [tool.ruff.lint.pylint]
@@ -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.3.dev1"
8
+ __version__ = "1.0.4.dev0"
@@ -136,6 +136,9 @@ class SearchAction(RegistryAction):
136
136
  "visibility": setup.visibility.value if setup.visibility else None,
137
137
  "status": setup.status.value if setup.status else None,
138
138
  "description": (setup.documentation or "")[: self._DOC_PREVIEW_CHARS],
139
+ # The shape of the configuration, so choosing a scope needs no second call:
140
+ # read a key from here and pass it to ``load``.
141
+ "structure": setup.structure,
139
142
  }
140
143
  for setup in usable[:cap]
141
144
  ]
@@ -166,6 +169,15 @@ class UpdateAction(RegistryAction):
166
169
  "without changing what the instance currently serves, then activate it later with "
167
170
  "``set_version``.",
168
171
  )
172
+ structure: dict[str, str] | None = Field(
173
+ default=None,
174
+ description="Refreshed map of key path -> one-line summary of what lives at it, "
175
+ "describing the content this call carries. Same form as on create: summarise what each "
176
+ 'key is FOR, join nested keys with "." (llm.model), bracket-quote a key containing '
177
+ '. [ ] " or \\ (limits["max.tokens"]), index a list element (tools[0]). Omitting it '
178
+ "replaces the stored map with one derived from the raw values, losing every written "
179
+ "summary — supply it whenever the instance had one.",
180
+ )
169
181
 
170
182
  async def execute(self, ctx: RegistryActionCtx) -> Any:
171
183
  """Cut a new version of the setup's content and rename it.
@@ -184,6 +196,7 @@ class UpdateAction(RegistryAction):
184
196
  "name": self.name,
185
197
  "content": self.content,
186
198
  "set_as_current": self.set_as_current,
199
+ "structure": self.structure,
187
200
  })
188
201
 
189
202
 
@@ -346,7 +346,11 @@ class RegistryObjectToolKit(DkToolkit):
346
346
  Also echoes ``visibility`` back in the caller's vocabulary — the input enum is
347
347
  ``public``/``private``/``internal`` but the backend returns the proto name
348
348
  ``VISIBILITY_INTERNAL``, so a naive round-trip fails. Strip the prefix and
349
- lower-case it so the field read back matches the field written.
349
+ lower-case it so the field read back matches the field written. Confined to the
350
+ model branch on purpose: every action carrying a real setup visibility returns a
351
+ ``SetupData``, while the actions returning a plain dict return a *configuration*
352
+ (``load``) or its key map (``structure``), where a key called ``visibility`` is the
353
+ service's own data and rewriting it would corrupt what the caller asked for.
350
354
 
351
355
  Args:
352
356
  value: A Pydantic model, proto message, or plain scalar/collection.
@@ -78,7 +78,63 @@ class LoadToolAction(LoadAction):
78
78
  action: Literal["tool"] = "tool"
79
79
  setup_id: str = Field(..., description="The tool's setup id (from a tools_manager search/get) to load.")
80
80
 
81
- async def execute(self, ctx: LoadActionCtx) -> LoadOutcome: # noqa: C901, PLR0911 — each return is a distinct, LLM-readable outcome
81
+ async def _duplicate_outcome(self, ctx: LoadActionCtx, module_id: str) -> LoadOutcome | None:
82
+ """Resolve the two "already there" cases, or ``None`` if this is a genuinely new load.
83
+
84
+ Runs BEFORE ``resolve_tool``: ``module_id`` is already known from the registry lookup, so
85
+ a repeat load costs no schema fetch. Reads ``base_tools`` — what is callable right now —
86
+ which after rehydration also covers a tool loaded on an earlier turn of this mission.
87
+
88
+ Args:
89
+ ctx: The load context carrying the live tool list and the module context.
90
+ module_id: The requested setup's module, from the registry lookup.
91
+
92
+ Returns:
93
+ An ``already_loaded`` success, a conflict failure, or ``None`` to continue loading.
94
+ """
95
+ # Imported here, not at module top: ModuleToolkit requires the optional agno dependency at
96
+ # import time, while this module must stay importable without it (same convention as the
97
+ # rest of community.agno).
98
+ from digitalkin.community.agno.module_toolkit import ModuleToolkit
99
+
100
+ loaded = [tool for tool in ctx.base_tools if isinstance(tool, ModuleToolkit)]
101
+ existing = next((tool for tool in loaded if tool.tool_module_info.setup_id == self.setup_id), None)
102
+ if existing is not None:
103
+ # Re-persist rather than just report: the id is only durable if an earlier turn's write
104
+ # actually landed, and that write is fail-soft. Without this, one failed persist makes
105
+ # the tool re-loadable forever but never durable — the model keeps getting "already
106
+ # loaded" and the record never appears. The upsert is a no-op when it did land.
107
+ # Setup-declared tools are excluded: they need no mission record.
108
+ if self.setup_id not in ctx.context.tool_cache.declared:
109
+ await ctx.context.persist_loaded_tool(self.setup_id)
110
+ info = existing.tool_module_info
111
+ name = info.tool_name or info.module_name or info.slug
112
+ # Name the callable functions (they ARE callable right now) so an already-loaded result
113
+ # is as verifiable as a fresh load, instead of an empty list reading as "nothing to call".
114
+ callable_names = sorted({*existing.functions, *existing.async_functions})
115
+ listed = f" You can now call: {', '.join(callable_names)}." if callable_names else ""
116
+ return LoadOutcome(
117
+ ok=True,
118
+ status="already_loaded",
119
+ tool_name=name,
120
+ loaded_functions=callable_names,
121
+ message=f"'{name}' is already loaded; call it directly.{listed}",
122
+ )
123
+ # A *different* setup of an already-loaded module cannot rebind — the live binding wins
124
+ # server-side, so appending it would only add duplicate tool names and confirm a change that
125
+ # never takes effect. Refuse explicitly instead of lying.
126
+ conflict = next((tool for tool in loaded if tool.tool_module_info.module_id == module_id), None)
127
+ if conflict is not None:
128
+ return LoadOutcome(
129
+ ok=False,
130
+ message=(
131
+ f"could not load setup {self.setup_id}: its tool module is already loaded via setup "
132
+ f"{conflict.tool_module_info.setup_id}, whose configuration stays in effect"
133
+ ),
134
+ )
135
+ return None
136
+
137
+ async def execute(self, ctx: LoadActionCtx) -> LoadOutcome: # ruff: ignore[complex-structure, too-many-return-statements] — each return is a distinct, LLM-readable outcome
82
138
  """Resolve the setup into a ModuleToolkit and append it to the live tool list.
83
139
 
84
140
  Idempotent per ``setup_id``; never raises. The setup's family is read first so a
@@ -125,7 +181,11 @@ class LoadToolAction(LoadAction):
125
181
  ),
126
182
  )
127
183
 
128
- # Confirmed tool module — resolve it into a callable toolkit.
184
+ duplicate = await self._duplicate_outcome(ctx, setup.module_id)
185
+ if duplicate is not None:
186
+ return duplicate
187
+
188
+ # Confirmed tool module, not already loaded — resolve it into a callable toolkit.
129
189
  try:
130
190
  info = await ctx.context.resolve_tool(self.setup_id)
131
191
  except PermissionDeniedError:
@@ -140,42 +200,15 @@ class LoadToolAction(LoadAction):
140
200
  ok=False, message=f"could not load setup {self.setup_id}: this tool module exposes no callable tools"
141
201
  )
142
202
 
143
- # Imported here, not at module top: ModuleToolkit requires the optional agno dependency at
144
- # import time, while this module must stay importable without it (same convention as the
145
- # rest of community.agno).
146
203
  from digitalkin.community.agno.module_toolkit import ModuleToolkit
147
204
 
148
205
  name = info.tool_name or info.module_name or info.slug
149
- loaded = [tool for tool in ctx.base_tools if isinstance(tool, ModuleToolkit)]
150
- # Idempotent: re-loading the exact same setup is a no-op success. Still name the callable
151
- # functions (they ARE callable right now) so an already-loaded result is as verifiable as a
152
- # fresh load, instead of an empty ``loaded_functions`` that reads as "nothing to call".
153
- existing = next((tool for tool in loaded if tool.tool_module_info.setup_id == self.setup_id), None)
154
- if existing is not None:
155
- callable_names = sorted({*existing.functions, *existing.async_functions})
156
- listed = f" You can now call: {', '.join(callable_names)}." if callable_names else ""
157
- return LoadOutcome(
158
- ok=True,
159
- status="already_loaded",
160
- tool_name=name,
161
- loaded_functions=callable_names,
162
- message=f"'{name}' is already loaded; call it directly.{listed}",
163
- )
164
- # A *different* setup of an already-loaded module cannot rebind — the live binding wins
165
- # server-side, so appending it would only add duplicate tool names and confirm a change that
166
- # never takes effect. Refuse explicitly instead of lying.
167
- conflict = next((tool for tool in loaded if tool.tool_module_info.module_id == info.module_id), None)
168
- if conflict is not None:
169
- return LoadOutcome(
170
- ok=False,
171
- message=(
172
- f"could not load setup {self.setup_id}: its tool module is already loaded via setup "
173
- f"{conflict.tool_module_info.setup_id}, whose configuration stays in effect"
174
- ),
175
- )
176
-
177
206
  toolkit = ModuleToolkit(ctx.context, info)
178
207
  ctx.base_tools.append(toolkit)
208
+ # Persist the id so the load outlives this turn. ``resolve_tool`` only reached the
209
+ # mission-scoped ``dynamic`` cache layer, which is rebuilt from scratch on the next
210
+ # user message; without this the tool would have to be re-loaded every turn.
211
+ await ctx.context.persist_loaded_tool(self.setup_id)
179
212
  await ctx.notify("tool_loaded", {"setup_id": self.setup_id, "tool_name": name})
180
213
  # Name the now-callable functions so the model can verify and call them directly.
181
214
  callable_names = sorted({*toolkit.functions, *toolkit.async_functions})
@@ -63,7 +63,7 @@ class LoadManager(DkToolkit):
63
63
  """
64
64
  self._base_tools = base_tools
65
65
 
66
- async def load_manager(self, action: LoadActions) -> str: # noqa: ARG002 — schema-only stub, never run
66
+ async def load_manager(self, action: LoadActions) -> str: # ruff: ignore[unused-method-argument] — schema-only stub, never run
67
67
  """Load a discovered object into the agent so it becomes usable right now.
68
68
 
69
69
  Loading is a two-step flow, and this is step two: first DISCOVER the object with its
@@ -0,0 +1,151 @@
1
+ """Actions for the ``services_manager`` dispatcher.
2
+
3
+ Adds the two service-specific actions to the shared CRUD + search set:
4
+
5
+ - ``create`` — create a shareable service from a name + configuration JSON;
6
+ - ``structure`` — show a service's key paths and what lives at each, without its content;
7
+ - ``load`` — return the service's stored JSON configuration content, whole or one key of
8
+ it (distinct from Tool.load, which loads a live tool into the agent).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal
14
+
15
+ from pydantic import Field
16
+
17
+ from digitalkin.community.agno.toolkits.registry.action import (
18
+ ChangeVisibilityAction,
19
+ DeleteAction,
20
+ GetAction,
21
+ ListVersionsAction,
22
+ SearchAction,
23
+ SetVersionAction,
24
+ UpdateAction,
25
+ )
26
+ from digitalkin.community.agno.toolkits.registry.base import RegistryAction
27
+ from digitalkin.utils.json_structure import JsonStructure
28
+
29
+ if TYPE_CHECKING:
30
+ from digitalkin.community.agno.toolkits.registry.base import RegistryActionCtx
31
+
32
+
33
+ class CreateServiceAction(RegistryAction):
34
+ """Create a shareable service other kins can discover.
35
+
36
+ Only a name and the configuration JSON are needed — owner, organisation and kind
37
+ are derived server-side. Once created it is discoverable via ``search`` and
38
+ readable via ``load``.
39
+ The service is always created *private* (owner only): visibility is not a creation
40
+ parameter. Widening it to ``internal`` (whole organisation) or ``public`` (everyone)
41
+ requires a separate ``change_visibility`` call.
42
+ """
43
+
44
+ action: Literal["create"] = "create"
45
+ writes: ClassVar[bool] = True
46
+ name: str = Field(..., description="Human-readable service name.")
47
+ content: dict[str, Any] = Field(
48
+ ...,
49
+ min_length=1,
50
+ description="The service configuration (a non-empty JSON object). "
51
+ "Note: JSON numbers round-trip as floats over the wire.",
52
+ )
53
+ structure: dict[str, str] = Field(
54
+ ...,
55
+ description="Map of key path -> one-line summary of what lives at it. This is what "
56
+ "another agent reads to decide which part of the configuration to fetch, so summarise "
57
+ "what the key is FOR, not what its value is, and keep every line far shorter than the "
58
+ "content it describes. Cover each key worth finding on its own; point at a whole "
59
+ "section instead when it is only ever read as a unit. Path syntax: join nested keys "
60
+ 'with "." (llm.model); bracket-quote a key containing . [ ] " or \\ '
61
+ '(limits["max.tokens"]); index a list element (tools[0]). Paths that do not exist in '
62
+ "content are dropped.",
63
+ )
64
+
65
+ async def execute(self, ctx: RegistryActionCtx) -> Any:
66
+ """Create the service setup from its name, content and authored key map.
67
+
68
+ Returns:
69
+ The created service setup.
70
+ """
71
+ return await ctx.setup.create_service_setup(self.name, self.content, self.structure)
72
+
73
+
74
+ class StructureServiceAction(RegistryAction):
75
+ """Show a service's shape — key paths and what lives at each — without its content.
76
+
77
+ Use it on a setup id you already hold; ``search`` already returns the same map on
78
+ every row, so there is no need to call this straight after a search. Feed a key from
79
+ it to ``load`` to read just that part of the configuration.
80
+ """
81
+
82
+ action: Literal["structure"] = "structure"
83
+ setup_id: str = Field(..., description="The service setup id whose shape to show.")
84
+
85
+ async def execute(self, ctx: RegistryActionCtx) -> Any:
86
+ """Return the stored ``{key path: summary}`` map, with no configuration content.
87
+
88
+ The map is written by whoever created or updated the setup, and the only read that
89
+ carries it is the setup search — so this restates a search for one id rather than
90
+ deriving a map locally, which would discard the written summaries. A setup stored
91
+ before the map existed returns an empty one.
92
+
93
+ Returns:
94
+ The key map, or an empty dict when the setup carries none.
95
+ """
96
+ await ctx.ensure_kind(self.setup_id)
97
+ found = await ctx.registry.search_setups(setup_ids=[self.setup_id], module_types=[ctx.module_type], limit=1)
98
+ return found[0].structure if found else {}
99
+
100
+
101
+ class LoadServiceAction(RegistryAction):
102
+ """Load a service's configuration — one key from its structure, or the whole document."""
103
+
104
+ action: Literal["load"] = "load"
105
+ setup_id: str = Field(..., description="The service setup id to load (from a search result).")
106
+ key: str | None = Field(
107
+ default=None,
108
+ description="One key path copied verbatim from the service's structure map, to read just "
109
+ "that part of the configuration. Omit to load the whole document — do that only when the "
110
+ "configuration is small or genuinely needed in full.",
111
+ )
112
+
113
+ async def execute(self, ctx: RegistryActionCtx) -> Any:
114
+ """Return the service's configuration content, or the part ``key`` names.
115
+
116
+ Guards the object type first: without it ``load`` would happily return a tool's
117
+ internal configuration — the most dangerous type-confusion, since the response
118
+ carries no field the caller could use to notice it read the wrong kind. That guard
119
+ already reads the whole setup, so the key is applied to the content in hand rather
120
+ than costing a second scoped fetch.
121
+
122
+ Returns:
123
+ The value at ``key``, or the whole configuration JSON object when no key is given.
124
+
125
+ Raises:
126
+ ValueError: ``key`` names a path the configuration does not have.
127
+ """
128
+ setup = await ctx.ensure_kind(self.setup_id)
129
+ content = setup.current_setup_version.content
130
+ if self.key is None:
131
+ return content
132
+ found = JsonStructure.resolve(content, [self.key])
133
+ if self.key not in found:
134
+ msg = f"{self.key!r} is not a key of this configuration; copy one from its structure"
135
+ raise ValueError(msg)
136
+ return found[self.key]
137
+
138
+
139
+ ServiceActions = Annotated[
140
+ GetAction
141
+ | CreateServiceAction
142
+ | SearchAction
143
+ | StructureServiceAction
144
+ | LoadServiceAction
145
+ | UpdateAction
146
+ | DeleteAction
147
+ | ChangeVisibilityAction
148
+ | ListVersionsAction
149
+ | SetVersionAction,
150
+ Field(discriminator="action"),
151
+ ]
@@ -37,11 +37,15 @@ class ServicesManager(RegistryObjectToolKit):
37
37
  name="services_manager",
38
38
  actions=ServiceActions,
39
39
  description=(
40
- "Manage Service SETUPS: create, search, load, update, delete, change_visibility, plus "
41
- "list_versions / set_version to inspect the configuration history and undo a bad "
42
- "update. The "
43
- "action discriminator selects the operation; 'load' returns a service's configuration "
44
- "content for use."
40
+ "Manage Service SETUPS: create, search, structure, load, update, delete, "
41
+ "change_visibility, plus list_versions / set_version to inspect the configuration "
42
+ "history and undo a bad update. The action discriminator selects the operation. "
43
+ "Configurations can be large, so read them in two steps: 'search' returns each "
44
+ "result with a 'structure' map of key path -> what lives there ('structure' fetches "
45
+ "the same map for an id you already hold), then 'load' with a key copied verbatim "
46
+ "from it returns just that part. Load without a key only when the whole document is "
47
+ "genuinely needed. On create and update you write that map yourself, describing what "
48
+ "each key is for — it is how other agents find their way around the configuration."
45
49
  ),
46
50
  entrypoint=self.services_manager,
47
51
  )
@@ -186,7 +186,7 @@ class SingleJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
186
186
  data = output_data.model_dump(mode="json")
187
187
 
188
188
  # Lock guards only the session validity check; queue.put() runs outside.
189
- async with session._write_lock: # noqa: SLF001
189
+ async with session._write_lock: # ruff: ignore[private-member-access]
190
190
  if self.tasks_sessions.get(job_id) is None:
191
191
  logger.debug("Queue write rejected - session removed during lock wait", extra={"job_id": job_id})
192
192
  return
@@ -55,7 +55,7 @@ class TaskProfiler:
55
55
  for stale in candidates[keep_n:]:
56
56
  try:
57
57
  stale.unlink()
58
- except OSError: # noqa: PERF203
58
+ except OSError: # ruff: ignore[try-except-in-loop]
59
59
  logger.debug("Profiler rotation: could not delete %s", stale)
60
60
 
61
61
  def start(self) -> None:
@@ -63,7 +63,7 @@ class TaskProfiler:
63
63
  if self._mode == ProfilerMode.NONE:
64
64
  return
65
65
 
66
- try: # noqa: PLW0717
66
+ try: # ruff: ignore[too-many-statements-in-try-clause]
67
67
  os.makedirs(self._output_dir, exist_ok=True)
68
68
 
69
69
  if self._mode == ProfilerMode.VIZTRACER:
@@ -100,7 +100,7 @@ class TaskProfiler:
100
100
  if self._profiler is None and not self._yappi_started:
101
101
  return
102
102
 
103
- try: # noqa: PLW0717
103
+ try: # ruff: ignore[too-many-statements-in-try-clause]
104
104
  timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%dT%H%M%S%f")
105
105
  base = f"{self._task_id}_{timestamp}"
106
106
 
@@ -78,7 +78,7 @@ class BaseTaskManager(ABC):
78
78
  session = self.tasks_sessions.get(task_id)
79
79
  if session is not None:
80
80
  # Close stream under the write lock so pending writes see stream_closed.
81
- async with session._write_lock: # noqa: SLF001
81
+ async with session._write_lock: # ruff: ignore[private-member-access]
82
82
  session.close_stream()
83
83
 
84
84
  session = self.tasks_sessions.pop(task_id, None)
@@ -49,7 +49,7 @@ class LocalTaskManager(BaseTaskManager):
49
49
  """
50
50
  await self._acquire_task_slot(coro)
51
51
  registered = False
52
- try: # noqa: PLW0717
52
+ try: # ruff: ignore[too-many-statements-in-try-clause]
53
53
  async with self._tasks_lock:
54
54
  await self._validate_task_creation(task_id, mission_id, coro)
55
55
  session = self._create_session(task_id, mission_id, module)
@@ -43,7 +43,7 @@ class ModuleRunner:
43
43
  self._redis_client = redis_client
44
44
  self._servicer = servicer
45
45
 
46
- async def run( # noqa: C901, PLR0914, PLR0915
46
+ async def run( # ruff: ignore[complex-structure, too-many-locals, too-many-statements]
47
47
  self,
48
48
  query: struct_pb2.Struct,
49
49
  *,
@@ -80,11 +80,11 @@ class ModuleRunner:
80
80
 
81
81
  top_level_keys: list[str] = []
82
82
  query_byte_size = 0
83
- try: # noqa: PLW0717
83
+ try: # ruff: ignore[too-many-statements-in-try-clause]
84
84
  timer.mark("entry")
85
85
  profiler.start()
86
86
 
87
- try: # noqa: PLW0717
87
+ try: # ruff: ignore[too-many-statements-in-try-clause]
88
88
  setup_version = await self._servicer.resolve_setup(setup_id, mission_id)
89
89
  timer.mark("setup_resolve")
90
90
 
@@ -93,8 +93,8 @@ class ModuleRunner:
93
93
 
94
94
  tool_cache = self._servicer.get_tool_cache(setup_version.setup_id)
95
95
  if tool_cache is None:
96
- registry = self._servicer._get_registry() # noqa: SLF001
97
- communication = self._servicer._get_communication() # noqa: SLF001
96
+ registry = self._servicer._get_registry() # ruff: ignore[private-member-access]
97
+ communication = self._servicer._get_communication() # ruff: ignore[private-member-access]
98
98
  if registry is not None and communication is not None:
99
99
  tool_cache = await self._servicer.get_or_build_tool_cache(
100
100
  setup_version.setup_id,
@@ -207,7 +207,7 @@ class ModuleRunner:
207
207
 
208
208
  except ValidationError as exc:
209
209
  input_format_cls = (
210
- self._servicer.module_class._extended_input_format # noqa: SLF001
210
+ self._servicer.module_class._extended_input_format # ruff: ignore[private-member-access]
211
211
  or self._servicer.module_class.input_format
212
212
  )
213
213
  model_name = input_format_cls.__name__ if input_format_cls is not None else "<unknown>"
@@ -69,7 +69,7 @@ class ProtoStreamReader:
69
69
  """Persist the current cursor to Redis."""
70
70
  await self._redis_client.set(self._cursor_key, self._last_id, ex=get_gateway_settings().stream.redis_cursor_ttl)
71
71
 
72
- async def read_structs( # noqa: C901
72
+ async def read_structs( # ruff: ignore[complex-structure]
73
73
  self,
74
74
  count: int = 50,
75
75
  cursor_save_interval: int = 100,
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
26
26
  import builtins
27
27
 
28
28
 
29
- class RedisClient: # noqa: PLR0904
29
+ class RedisClient: # ruff: ignore[too-many-public-methods]
30
30
  """Redis connection pool manager with split read/write pools.
31
31
 
32
32
  Attributes: