digitalkin 1.0.2.dev0__tar.gz → 1.0.2.dev2__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 (250) hide show
  1. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/PKG-INFO +2 -2
  2. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/pyproject.toml +2 -2
  3. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/hitl.py +116 -16
  5. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/__init__.py +4 -0
  6. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/base.py +14 -2
  7. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/defaults.py +15 -3
  8. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/registry.py +57 -11
  9. digitalkin-1.0.2.dev2/src/digitalkin/community/agno/toolkits/setup.py +204 -0
  10. digitalkin-1.0.2.dev2/src/digitalkin/community/agno/toolkits/tool_loader.py +139 -0
  11. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/job_manager/base_job_manager.py +2 -0
  12. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/job_manager/single_job_manager.py +12 -0
  13. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/module_runner.py +5 -0
  14. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/module_servicer.py +14 -4
  15. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/module_context.py +67 -1
  16. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/services/registry.py +1 -0
  17. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/filesystem/grpc_filesystem.py +29 -22
  18. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/default_registry.py +2 -2
  19. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/grpc_registry.py +44 -19
  20. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/registry_strategy.py +42 -2
  21. digitalkin-1.0.2.dev2/src/digitalkin/services/setup/default_setup.py +168 -0
  22. digitalkin-1.0.2.dev2/src/digitalkin/services/setup/grpc_setup.py +284 -0
  23. digitalkin-1.0.2.dev2/src/digitalkin/services/setup/setup_strategy.py +105 -0
  24. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/storage/grpc_storage.py +25 -6
  25. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin.egg-info/PKG-INFO +2 -2
  26. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin.egg-info/SOURCES.txt +2 -0
  27. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin.egg-info/requires.txt +1 -1
  28. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/tests/test_exceptions.py +2 -2
  29. digitalkin-1.0.2.dev0/src/digitalkin/services/setup/default_setup.py +0 -235
  30. digitalkin-1.0.2.dev0/src/digitalkin/services/setup/grpc_setup.py +0 -381
  31. digitalkin-1.0.2.dev0/src/digitalkin/services/setup/setup_strategy.py +0 -156
  32. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/LICENSE +0 -0
  33. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/README.md +0 -0
  34. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/__init__.py +0 -0
  35. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/mock/__init__.py +0 -0
  36. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/mock/mock_pb2.py +0 -0
  37. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  38. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/server_async_insecure.py +0 -0
  39. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/server_async_secure.py +0 -0
  40. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/server_sync_insecure.py +0 -0
  41. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/base_server/server_sync_secure.py +0 -0
  42. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/__init__.py +0 -0
  43. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/echo_module.py +0 -0
  44. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/models/__init__.py +0 -0
  45. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/models/input.py +0 -0
  46. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/models/output.py +0 -0
  47. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/models/secret.py +0 -0
  48. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/models/setup.py +0 -0
  49. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/server.py +0 -0
  50. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/triggers/__init__.py +0 -0
  51. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/bench_module/triggers/message_trigger.py +0 -0
  52. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/__init__.py +0 -0
  53. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/archetype_with_tools_module.py +0 -0
  54. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/cpu_intensive_module.py +0 -0
  55. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/dynamic_setup_module.py +0 -0
  56. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/minimal_llm_module.py +0 -0
  57. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/modules/text_transform_module.py +0 -0
  58. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  59. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  60. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  61. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  62. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  63. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/monitoring/tests/test_metrics.py +0 -0
  64. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/client.py +0 -0
  65. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/echo_module.py +0 -0
  66. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/models/__init__.py +0 -0
  67. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/models/input.py +0 -0
  68. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/models/output.py +0 -0
  69. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/models/secret.py +0 -0
  70. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/models/setup.py +0 -0
  71. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/server.py +0 -0
  72. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/triggers/__init__.py +0 -0
  73. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/redis_demo/triggers/message_trigger.py +0 -0
  74. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/services/filesystem_module.py +0 -0
  75. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/examples/services/storage_module.py +0 -0
  76. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/setup.cfg +0 -0
  77. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/__init__.py +0 -0
  78. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/__init__.py +0 -0
  79. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/__init__.py +0 -0
  80. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/agno_adapter.py +0 -0
  81. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/agui_tools.py +0 -0
  82. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/models.py +0 -0
  83. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/module_toolkit.py +0 -0
  84. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
  85. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
  86. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/__init__.py +0 -0
  87. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/common/__init__.py +0 -0
  88. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/common/factories.py +0 -0
  89. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/exceptions.py +0 -0
  90. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/job_manager/__init__.py +0 -0
  91. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/profiling/__init__.py +0 -0
  92. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/profiling/step_timer.py +0 -0
  93. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/profiling/task_profiler.py +0 -0
  94. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/resilience/__init__.py +0 -0
  95. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  96. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  97. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/__init__.py +0 -0
  98. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  99. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  100. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  101. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
  102. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
  103. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  104. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
  105. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/redis/redis_state.py +0 -0
  106. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  107. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  108. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/core/task_manager/task_session.py +0 -0
  109. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/exceptions.py +0 -0
  110. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/__init__.py +0 -0
  111. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  112. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  113. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/gateway_servicer.py +0 -0
  114. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  115. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
  116. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
  117. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
  118. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/module_server.py +0 -0
  119. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
  120. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  121. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  122. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  123. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  124. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  125. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  126. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
  127. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/logger.py +0 -0
  128. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/__init__.py +0 -0
  129. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/agui_mixin.py +0 -0
  130. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/base_mixin.py +0 -0
  131. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/cost_mixin.py +0 -0
  132. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  133. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  134. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/logger_mixin.py +0 -0
  135. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/mixins/storage_mixin.py +0 -0
  136. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/__init__.py +0 -0
  137. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/core/__init__.py +0 -0
  138. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/core/job_manager_models.py +0 -0
  139. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/core/redis.py +0 -0
  140. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/core/task_monitor.py +0 -0
  141. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/events/__init__.py +0 -0
  142. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/events/agent_events.py +0 -0
  143. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  144. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  145. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  146. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/models.py +0 -0
  147. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
  148. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/grpc_servers/types.py +0 -0
  149. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/__init__.py +0 -0
  150. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/ag_ui.py +0 -0
  151. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/base_types.py +0 -0
  152. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/module.py +0 -0
  153. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/module_types.py +0 -0
  154. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/request_metadata.py +0 -0
  155. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/select_schema.py +0 -0
  156. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/setup_types.py +0 -0
  157. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/tool_cache.py +0 -0
  158. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/tool_reference.py +0 -0
  159. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/module/utility.py +0 -0
  160. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/services/__init__.py +0 -0
  161. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/services/cost.py +0 -0
  162. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/services/services.py +0 -0
  163. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/services/storage.py +0 -0
  164. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/__init__.py +0 -0
  165. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/gateway.py +0 -0
  166. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/grpc_client.py +0 -0
  167. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/log.py +0 -0
  168. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/module.py +0 -0
  169. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/profiling.py +0 -0
  170. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/queue.py +0 -0
  171. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/redis.py +0 -0
  172. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/registry.py +0 -0
  173. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/resilience.py +0 -0
  174. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/server/__init__.py +0 -0
  175. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/server/channel.py +0 -0
  176. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/server/grpc.py +0 -0
  177. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/server/server.py +0 -0
  178. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/server/servicer.py +0 -0
  179. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/task_manager.py +0 -0
  180. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  181. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/settings/utils/channel.py +0 -0
  182. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/utils/__init__.py +0 -0
  183. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  184. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/__init__.py +0 -0
  185. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/_base_module.py +0 -0
  186. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/archetype_module.py +0 -0
  187. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/tool_module.py +0 -0
  188. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/trigger_handler.py +0 -0
  189. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/triggers/__init__.py +0 -0
  190. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  191. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  192. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  193. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/py.typed +0 -0
  194. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/__init__.py +0 -0
  195. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/base_strategy.py +0 -0
  196. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/communication/__init__.py +0 -0
  197. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  198. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/communication/default_communication.py +0 -0
  199. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/communication/exceptions.py +0 -0
  200. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  201. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/cost/__init__.py +0 -0
  202. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  203. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/cost/default_cost.py +0 -0
  204. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/cost/exceptions.py +0 -0
  205. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  206. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/filesystem/__init__.py +0 -0
  207. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  208. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  209. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  210. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/identity/__init__.py +0 -0
  211. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/identity/default_identity.py +0 -0
  212. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  213. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/__init__.py +0 -0
  214. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/exceptions.py +0 -0
  215. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/registry/registry_models.py +0 -0
  216. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/secret/__init__.py +0 -0
  217. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/secret/default_secret.py +0 -0
  218. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/secret/exceptions.py +0 -0
  219. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/secret/grpc_secret.py +0 -0
  220. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/secret/secret_strategy.py +0 -0
  221. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/services_config.py +0 -0
  222. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/services_models.py +0 -0
  223. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/setup/__init__.py +0 -0
  224. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/setup/exceptions.py +0 -0
  225. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/storage/__init__.py +0 -0
  226. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/storage/default_storage.py +0 -0
  227. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/storage/exceptions.py +0 -0
  228. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  229. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/task_manager/__init__.py +0 -0
  230. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
  231. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  232. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  233. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  234. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/user_profile/__init__.py +0 -0
  235. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  236. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  237. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  238. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  239. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/__init__.py +0 -0
  240. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/arg_parser.py +0 -0
  241. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/conditional_schema.py +0 -0
  242. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/development_mode_action.py +0 -0
  243. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/dynamic_schema.py +0 -0
  244. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/exceptions.py +0 -0
  245. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  246. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/package_discover.py +0 -0
  247. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/proto_utils.py +0 -0
  248. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin/utils/schema_splitter.py +0 -0
  249. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  250. {digitalkin-1.0.2.dev0 → digitalkin-1.0.2.dev2}/src/digitalkin.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.2.dev0
3
+ Version: 1.0.2.dev2
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.1.dev2
456
+ Requires-Dist: agentic-mesh-protocol==1.0.1.dev4
457
457
  Requires-Dist: anyio>=4.13.0
458
458
  Requires-Dist: grpcio-health-checking==1.82.1
459
459
  Requires-Dist: grpcio-reflection==1.82.1
@@ -28,7 +28,7 @@
28
28
 
29
29
  dependencies = [
30
30
  "ag-ui-protocol>=0.1.18",
31
- "agentic-mesh-protocol==1.0.1.dev2",
31
+ "agentic-mesh-protocol==1.0.1.dev4",
32
32
  "anyio>=4.13.0",
33
33
  "grpcio-health-checking==1.82.1",
34
34
  "grpcio-reflection==1.82.1",
@@ -37,7 +37,7 @@
37
37
  "pydantic>=2.12.4",
38
38
  "redis[hiredis]>=7.4.0,<9",
39
39
  ]
40
- version = "1.0.2.dev0"
40
+ version = "1.0.2.dev2"
41
41
 
42
42
  [project.optional-dependencies]
43
43
  agno = [ "agno>=2.6" ]
@@ -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.2.dev0"
8
+ __version__ = "1.0.2.dev2"
@@ -23,6 +23,7 @@ if TYPE_CHECKING:
23
23
  from agno.agent import Agent
24
24
  from agno.run.agent import RunOutput
25
25
 
26
+ from digitalkin.community.agno.toolkits.tool_loader import ToolLoaderTools
26
27
  from digitalkin.models.events import BaseAgentRunEvent
27
28
  from digitalkin.models.module import ModuleContext
28
29
  from digitalkin.services.storage import StorageStrategy
@@ -78,8 +79,10 @@ class PausedRunStore:
78
79
  seen: set[str] = set()
79
80
  pending: list[str] = []
80
81
  for tool in run_output.tools or []:
81
- tid = getattr(tool, "tool_call_id", None)
82
- if tid and tid not in seen and getattr(tool, "external_execution_required", False):
82
+ tid = tool.tool_call_id
83
+ # Skip tools already resolved in-process (e.g. a use_setup call handled by the
84
+ # runner): only genuinely unresolved external tools go to the front.
85
+ if tid and tid not in seen and tool.external_execution_required and tool.result is None:
83
86
  seen.add(tid)
84
87
  pending.append(tid)
85
88
  record = PausedRunRecord(
@@ -303,6 +306,7 @@ class AgnoHitlRunner:
303
306
  storage: StorageStrategy | None = None,
304
307
  store: PausedRunStore | None = None,
305
308
  dependency_key: str = "agui_tools",
309
+ tool_loader: ToolLoaderTools | None = None,
306
310
  ) -> None:
307
311
  """Initialize the runner.
308
312
 
@@ -314,6 +318,12 @@ class AgnoHitlRunner:
314
318
  store: Pre-built paused-run store; wins over ``storage``.
315
319
  dependency_key: Agno dependencies key carrying the AG-UI tool
316
320
  list (must match :func:`make_tools_factory`).
321
+ tool_loader: The :class:`ToolLoaderTools` bound to the agent's tool list
322
+ (``ToolLoaderTools.find(tools)``). When present, a ``use_setup`` pause is
323
+ resolved and the run auto-continues instead of surfacing to the front.
324
+ When omitted, the runner locates it in ``agent.tools`` itself — otherwise
325
+ a ``use_setup`` pause would surface to the front as a frontend tool no
326
+ client implements, wedging the thread.
317
327
 
318
328
  Raises:
319
329
  ValueError: If neither ``storage`` nor ``store`` is provided.
@@ -323,9 +333,18 @@ class AgnoHitlRunner:
323
333
  msg = "AgnoHitlRunner requires either `storage` or `store`."
324
334
  raise ValueError(msg)
325
335
  store = PausedRunStore(storage)
336
+ if tool_loader is None:
337
+ # Lazy import: ToolLoaderTools requires the optional agno dependency at
338
+ # import time, while this module must stay importable without it (same
339
+ # convention as the rest of community.agno). vars(): test fakes may not
340
+ # carry a tools attribute at all.
341
+ from digitalkin.community.agno.toolkits.tool_loader import ToolLoaderTools
342
+
343
+ tool_loader = ToolLoaderTools.find(vars(agent).get("tools"))
326
344
  self._agent = agent
327
345
  self._store = store
328
346
  self._dependency_key = dependency_key
347
+ self._tool_loader = tool_loader
329
348
 
330
349
  async def run(
331
350
  self,
@@ -360,7 +379,9 @@ class AgnoHitlRunner:
360
379
  yield_run_output=True,
361
380
  dependencies={self._dependency_key: agui_tools or []},
362
381
  )
363
- return await self._drive(stream=stream, send=send, thread_id=thread_id, run_output_cls=RunOutput)
382
+ return await self._drive(
383
+ stream=stream, send=send, thread_id=thread_id, run_output_cls=RunOutput, agui_tools=agui_tools
384
+ )
364
385
 
365
386
  async def continue_paused_run(
366
387
  self,
@@ -437,7 +458,9 @@ class AgnoHitlRunner:
437
458
  yield_run_output=True,
438
459
  dependencies={self._dependency_key: agui_tools or []},
439
460
  )
440
- pause_info = await self._drive(stream=stream, send=send, thread_id=thread_id, run_output_cls=RunOutput)
461
+ pause_info = await self._drive(
462
+ stream=stream, send=send, thread_id=thread_id, run_output_cls=RunOutput, agui_tools=agui_tools
463
+ )
441
464
 
442
465
  if pause_info is None:
443
466
  await self._store.delete(thread_id)
@@ -612,31 +635,108 @@ class AgnoHitlRunner:
612
635
  send: Callable[[BaseAgentRunEvent], Coroutine[Any, Any, None]],
613
636
  thread_id: str,
614
637
  run_output_cls: type[RunOutput],
638
+ agui_tools: list[AgUiTool] | None = None,
615
639
  ) -> PauseInfo | None:
616
- """Drain an Agno stream, forward events, persist on pause.
640
+ """Drain an Agno stream, forward events, and persist or auto-continue on pause.
641
+
642
+ A ``use_setup`` pause (dynamic tool load) is resolved in-process and the run
643
+ auto-continues with the enlarged tool list; a frontend-tool pause is persisted and
644
+ surfaced. The loop is bounded so a model that keeps calling ``use_setup`` cannot spin
645
+ forever.
646
+
647
+ Args:
648
+ stream: The Agno event stream to drain.
649
+ send: Digitalkin-event callback for each forwarded event.
650
+ thread_id: AG-UI thread identifier (storage key on a frontend pause).
651
+ run_output_cls: The ``RunOutput`` class used to spot the terminal run object.
652
+ agui_tools: Frontend tools to re-pass to Agno on an auto-continue.
617
653
 
618
654
  Returns:
619
- :class:`PauseInfo` on pause, ``None`` otherwise.
655
+ :class:`PauseInfo` on a frontend pause, ``None`` on completion.
620
656
  """
621
657
  from digitalkin.community.agno.agno_adapter import AgnoStreamAdapter
622
658
 
623
- adapter = AgnoStreamAdapter()
624
- final_run_output: RunOutput | None = None
659
+ for _ in range(20):
660
+ adapter = AgnoStreamAdapter()
661
+ final_run_output: RunOutput | None = None
625
662
 
626
- async for raw_event in stream:
627
- if isinstance(raw_event, run_output_cls):
628
- final_run_output = raw_event
629
- continue
630
- for event in adapter.to_digitalkin_events(raw_event):
663
+ async for raw_event in stream:
664
+ if isinstance(raw_event, run_output_cls):
665
+ final_run_output = raw_event
666
+ continue
667
+ for event in adapter.to_digitalkin_events(raw_event):
668
+ await send(event)
669
+
670
+ for event in adapter.flush():
631
671
  await send(event)
632
672
 
633
- for event in adapter.flush():
634
- await send(event)
673
+ if not (adapter.is_paused and final_run_output is not None and final_run_output.is_paused):
674
+ return None
675
+
676
+ # Resolve any use_setup calls in-process; if the pause has nothing left for the
677
+ # front, auto-continue so discover -> load -> use reads as a single turn.
678
+ if await self._load_paused_tools(final_run_output) and not self._pending_external(final_run_output):
679
+ stream = self._agent.acontinue_run(
680
+ run_response=final_run_output,
681
+ stream=True,
682
+ stream_events=True,
683
+ yield_run_output=True,
684
+ dependencies={self._dependency_key: agui_tools or []},
685
+ )
686
+ continue
635
687
 
636
- if adapter.is_paused and final_run_output is not None and getattr(final_run_output, "is_paused", False):
637
688
  pause_info = await self._store.save(run_output=final_run_output, thread_id=thread_id)
638
689
  # Attach AG-UI-shaped messages so the front can materialise the tool_call.
639
690
  pause_info.new_messages = HitlEvents.agno_messages_to_agui(final_run_output.messages or [])
640
691
  return pause_info
641
692
 
693
+ logger.warning("AgnoHitlRunner: auto-continue limit reached for thread_id=%s", thread_id)
694
+ from digitalkin.models.events import AgentRunEvent, RunErrorEvent
695
+
696
+ await send(
697
+ RunErrorEvent(
698
+ event=AgentRunEvent.RUN_ERROR,
699
+ error_type="auto_continue_limit",
700
+ content=(
701
+ "The run was stopped after too many consecutive in-process tool "
702
+ "loads (use_setup). Send a new message to continue."
703
+ ),
704
+ error_details=None,
705
+ timestamp=None,
706
+ metadata=None,
707
+ )
708
+ )
642
709
  return None
710
+
711
+ async def _load_paused_tools(self, run_output: RunOutput) -> bool:
712
+ """Resolve ``use_setup`` calls in a paused run, writing each tool result in place.
713
+
714
+ Args:
715
+ run_output: The paused Agno run.
716
+
717
+ Returns:
718
+ ``True`` if at least one ``use_setup`` call was handled, else ``False`` (no
719
+ loader wired, or the pause carries only frontend tools).
720
+ """
721
+ if self._tool_loader is None:
722
+ return False
723
+ handled = False
724
+ loader_tool = self._tool_loader.tool_name
725
+ for tool in run_output.tools or []:
726
+ if tool.external_execution_required and tool.result is None and tool.tool_name == loader_tool:
727
+ setup_id = (tool.tool_args or {}).get("setup_id", "")
728
+ tool.result = await self._tool_loader.load(setup_id)
729
+ handled = True
730
+ return handled
731
+
732
+ @staticmethod
733
+ def _pending_external(run_output: RunOutput) -> bool:
734
+ """Report whether any external tool in the paused run still needs a result.
735
+
736
+ Args:
737
+ run_output: The paused Agno run (after :meth:`_load_paused_tools`).
738
+
739
+ Returns:
740
+ ``True`` if a frontend tool call remains unresolved (must go to the front).
741
+ """
742
+ return any(tool.external_execution_required and tool.result is None for tool in run_output.tools or [])
@@ -9,6 +9,8 @@ from digitalkin.community.agno.toolkits.base import DkToolkit
9
9
  from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
10
10
  from digitalkin.community.agno.toolkits.defaults import DefaultToolkits
11
11
  from digitalkin.community.agno.toolkits.registry import RegistryTools
12
+ from digitalkin.community.agno.toolkits.setup import SetupTools
13
+ from digitalkin.community.agno.toolkits.tool_loader import ToolLoaderTools
12
14
  from digitalkin.community.agno.toolkits.user_profile import UserProfileTools
13
15
 
14
16
  __all__ = [
@@ -16,5 +18,7 @@ __all__ = [
16
18
  "DefaultToolkits",
17
19
  "DkToolkit",
18
20
  "RegistryTools",
21
+ "SetupTools",
22
+ "ToolLoaderTools",
19
23
  "UserProfileTools",
20
24
  ]
@@ -32,16 +32,28 @@ class DkToolkit(Toolkit):
32
32
  which pushes AG-UI custom events onto the caller's gRPC stream.
33
33
  """
34
34
 
35
- def __init__(self, name: str, tools: list[Any], context: ModuleContext | None = None) -> None:
35
+ def __init__(
36
+ self,
37
+ name: str,
38
+ tools: list[Any],
39
+ context: ModuleContext | None = None,
40
+ external_execution_required_tools: list[str] | None = None,
41
+ ) -> None:
36
42
  """Initialize the toolkit.
37
43
 
38
44
  Args:
39
45
  name: Toolkit name registered with Agno.
40
46
  tools: Bound tool callables to expose to the agent.
41
47
  context: Module context; when present, :meth:`_notify` can emit AG-UI events.
48
+ external_execution_required_tools: Tool names Agno must pause on (executed
49
+ outside the agent loop) instead of running their entrypoint.
42
50
  """
43
51
  self._ctx = context
44
- super().__init__(name=name, tools=tools)
52
+ super().__init__(
53
+ name=name,
54
+ tools=tools,
55
+ external_execution_required_tools=external_execution_required_tools or [],
56
+ )
45
57
 
46
58
  @staticmethod
47
59
  def _ok(output: Any, **metadata: Any) -> str:
@@ -6,6 +6,8 @@ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
8
8
  from digitalkin.community.agno.toolkits.registry import RegistryTools
9
+ from digitalkin.community.agno.toolkits.setup import SetupTools
10
+ from digitalkin.community.agno.toolkits.tool_loader import ToolLoaderTools
9
11
  from digitalkin.community.agno.toolkits.user_profile import UserProfileTools
10
12
 
11
13
  if TYPE_CHECKING:
@@ -33,18 +35,28 @@ class DefaultToolkits:
33
35
  def build(context: ModuleContext, session_id: str | None = None) -> list[Toolkit]:
34
36
  """Build the default toolkits from a module context.
35
37
 
38
+ Includes SetupTools only when ``context.setup`` is wired (the servicer's shared
39
+ setup service). ToolLoaderTools is always added and bound to the returned list so
40
+ dynamically-loaded tools land in the exact list the agent's factory splats.
41
+
36
42
  Args:
37
- context: The module context carrying the user_profile and registry services.
43
+ context: The module context carrying the services and (optional) setup service.
38
44
  session_id: The Agno session whose chat history should be readable.
39
45
 
40
46
  Returns:
41
- [ChatHistoryTools, UserProfileTools, RegistryTools].
47
+ [ChatHistoryTools, UserProfileTools, RegistryTools, (SetupTools?), ToolLoaderTools].
42
48
  """
43
- return [
49
+ tools: list[Toolkit] = [
44
50
  ChatHistoryTools(session_id=session_id, context=context),
45
51
  UserProfileTools(context.user_profile, context=context),
46
52
  RegistryTools(context.registry, context=context),
47
53
  ]
54
+ if context.setup is not None:
55
+ tools.append(SetupTools(context.setup, context=context))
56
+ loader = ToolLoaderTools(context=context)
57
+ tools.append(loader)
58
+ loader.bind_tools(tools)
59
+ return tools
48
60
 
49
61
  @staticmethod
50
62
  def bind_host(tools: list[Any] | Callable[..., list[Any]] | None, host: Any) -> None:
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from typing import TYPE_CHECKING, ClassVar, Literal
6
6
 
7
7
  from digitalkin.community.agno.toolkits.base import DkToolkit
8
+ from digitalkin.grpc_servers.exceptions import PermissionDeniedError
8
9
  from digitalkin.logger import logger
9
10
  from digitalkin.models.services.registry import RegistryModuleType, RegistrySetupStatus
10
11
  from digitalkin.services.registry.exceptions import RegistryServiceError
@@ -36,7 +37,7 @@ class RegistryTools(DkToolkit):
36
37
  self._registry = registry
37
38
  super().__init__(
38
39
  name="registry_tools",
39
- tools=[self.search_setups, self.search_modules],
40
+ tools=[self.search_setups, self.search_modules, self.get_service_setup],
40
41
  context=context,
41
42
  )
42
43
 
@@ -48,10 +49,10 @@ class RegistryTools(DkToolkit):
48
49
  kind: The requested kind filter.
49
50
 
50
51
  Returns:
51
- Error message when ``kind`` is neither 'tool' nor 'kin', else None.
52
+ Error message when ``kind`` is not 'tool', 'kin' or 'service', else None.
52
53
  """
53
- if kind is not None and kind not in {"tool", "kin"}:
54
- return f"invalid kind '{kind}'; use 'tool' or 'kin'"
54
+ if kind is not None and kind not in {"tool", "kin", "service"}:
55
+ return f"invalid kind '{kind}'; use 'tool', 'kin' or 'service'"
55
56
  return None
56
57
 
57
58
  def _clamp(self, limit: int) -> int:
@@ -66,16 +67,16 @@ class RegistryTools(DkToolkit):
66
67
  return min(max(limit, 1), self._MAX_RESULTS)
67
68
 
68
69
  async def search_setups(
69
- self, query: str | None = None, kind: Literal["tool", "kin"] | None = None, limit: int = 10
70
+ self, query: str | None = None, kind: Literal["tool", "kin", "service"] | None = None, limit: int = 10
70
71
  ) -> str:
71
- """Search ready-to-use setups (configured agent/tool instances you can actually invoke).
72
+ """Search ready-to-use setups (configured agent/tool/service instances you can actually invoke).
72
73
 
73
74
  A setup is an installed, configured instance of a module — the thing you can
74
- call. Use this to discover which tools or agents (kins) are available.
75
+ call. Use this to discover which tools, agents (kins) or services are available.
75
76
 
76
77
  Args:
77
78
  query: Free text matched against setup name and documentation. Omit to list all.
78
- kind: Optional filter: "tool" (invocable tools) or "kin" (agents).
79
+ kind: Optional filter: "tool" (invocable tools), "kin" (agents) or "service".
79
80
  limit: Max results (default 10, max 25).
80
81
 
81
82
  Returns:
@@ -89,12 +90,24 @@ class RegistryTools(DkToolkit):
89
90
  try:
90
91
  setups = await self._registry.search_setups(
91
92
  query=query,
92
- module_types=[RegistryModuleType.ARCHETYPE if kind == "kin" else RegistryModuleType.TOOL_MODULE]
93
+ module_types=[
94
+ {
95
+ "tool": RegistryModuleType.TOOL_MODULE,
96
+ "kin": RegistryModuleType.ARCHETYPE,
97
+ "service": RegistryModuleType.SERVICE,
98
+ }[kind]
99
+ ]
93
100
  if kind
94
101
  else None,
95
102
  statuses=[RegistrySetupStatus.READY, RegistrySetupStatus.CONFIGURATION_SUCCEEDED],
96
103
  limit=cap,
97
104
  )
105
+ except PermissionDeniedError:
106
+ return self._fail("permission denied: search_setups", tool="search_setups")
107
+ except ValueError as error:
108
+ # Enum encoding drift (fail-closed): permanent, retrying will not help.
109
+ logger.error("RegistryTools: setup search filter rejected: %s", error)
110
+ return self._fail("search filter not supported by this registry version", tool="search_setups")
98
111
  except RegistryServiceError as error:
99
112
  logger.warning("RegistryTools: setup search failed: %s", error)
100
113
  return self._fail(self._UNAVAILABLE, tool="search_setups")
@@ -115,8 +128,33 @@ class RegistryTools(DkToolkit):
115
128
  tool="search_setups",
116
129
  )
117
130
 
131
+ async def get_service_setup(self, setup_id: str) -> str:
132
+ """Fetch a service's configuration content (a JSON document) by setup id.
133
+
134
+ Use after discovering a service via ``search_setups`` and the user accepted it:
135
+ pass the proposed setup's ``setup_id`` to read the service content. Always
136
+ returns the latest version.
137
+
138
+ Args:
139
+ setup_id: The service setup id (from a ``search_setups`` result).
140
+
141
+ Returns:
142
+ The canonical envelope; ``output`` = the service configuration JSON object.
143
+ """
144
+ try:
145
+ content = await self._registry.get_service_setup(setup_id)
146
+ except PermissionDeniedError:
147
+ return self._fail("permission denied: get_service_setup", tool="get_service_setup")
148
+ except RegistryServiceError as error:
149
+ logger.warning("RegistryTools: service setup fetch failed: %s", error)
150
+ return self._fail(self._UNAVAILABLE, tool="get_service_setup")
151
+
152
+ if content is None:
153
+ return self._fail(f"service setup '{setup_id}' not found or has no content", tool="get_service_setup")
154
+ return self._ok(content, tool="get_service_setup")
155
+
118
156
  async def search_modules(
119
- self, query: str | None = None, kind: Literal["tool", "kin"] | None = None, limit: int = 10
157
+ self, query: str | None = None, kind: Literal["tool", "kin", "service"] | None = None, limit: int = 10
120
158
  ) -> str:
121
159
  """Search the module catalog (module TYPES, not configured instances).
122
160
 
@@ -126,7 +164,7 @@ class RegistryTools(DkToolkit):
126
164
 
127
165
  Args:
128
166
  query: Free text matched against module names. Omit to list all.
129
- kind: Optional filter: "tool" or "kin" (agents/archetypes).
167
+ kind: Optional filter: "tool", "kin" (agents/archetypes) or "service".
130
168
  limit: Max results (default 10, max 25).
131
169
 
132
170
  Returns:
@@ -141,10 +179,18 @@ class RegistryTools(DkToolkit):
141
179
  pending = self._registry.search_tools(name=query, limit=cap)
142
180
  elif kind == "kin":
143
181
  pending = self._registry.search_kins(name=query, limit=cap)
182
+ elif kind == "service":
183
+ pending = self._registry.search_services(name=query, limit=cap)
144
184
  else:
145
185
  pending = self._registry.search(name=query, limit=cap)
146
186
  try:
147
187
  modules = await pending
188
+ except PermissionDeniedError:
189
+ return self._fail("permission denied: search_modules", tool="search_modules")
190
+ except ValueError as error:
191
+ # Enum encoding drift (fail-closed): permanent, retrying will not help.
192
+ logger.error("RegistryTools: module search filter rejected: %s", error)
193
+ return self._fail("search filter not supported by this registry version", tool="search_modules")
148
194
  except RegistryServiceError as error:
149
195
  logger.warning("RegistryTools: module search failed: %s", error)
150
196
  return self._fail(self._UNAVAILABLE, tool="search_modules")