digitalkin 1.0.5.dev3__tar.gz → 1.0.5.dev5__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 (272) hide show
  1. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/PKG-INFO +2 -2
  2. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/client.py +52 -155
  3. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/pyproject.toml +2 -2
  4. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/__version__.py +1 -1
  5. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/agno_adapter.py +20 -0
  6. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/hitl.py +27 -5
  7. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/module_toolkit.py +21 -4
  8. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/action.py +19 -11
  9. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/base.py +22 -0
  10. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/services/action.py +10 -10
  11. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +1 -1
  12. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/module_runner.py +40 -2
  13. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/redis/redis_signal.py +2 -2
  14. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/gateway_servicer.py +69 -75
  15. digitalkin-1.0.5.dev5/src/digitalkin/grpc_servers/interceptors/validation.py +81 -0
  16. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/m2m_call_registry.py +3 -3
  17. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/module_server.py +39 -31
  18. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/module_servicer.py +130 -140
  19. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +43 -1
  20. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/agui_mixin.py +175 -9
  21. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/module_context.py +8 -1
  22. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/tool_cache.py +1 -0
  23. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/utility.py +6 -0
  24. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/registry.py +13 -9
  25. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/gateway.py +2 -2
  26. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/module.py +8 -0
  27. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/_base_module.py +75 -5
  28. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/communication/communication_strategy.py +6 -1
  29. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/communication/default_communication.py +7 -6
  30. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/communication/exceptions.py +8 -1
  31. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/communication/grpc_communication.py +48 -38
  32. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/cost/cost_strategy.py +1 -1
  33. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/cost/default_cost.py +17 -24
  34. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/cost/grpc_cost.py +115 -66
  35. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/filesystem/filesystem_strategy.py +2 -2
  36. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/filesystem/grpc_filesystem.py +127 -81
  37. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/registry/__init__.py +0 -2
  38. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/registry/default_registry.py +2 -22
  39. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/registry/grpc_registry.py +111 -125
  40. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/registry/registry_strategy.py +2 -6
  41. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/secret/grpc_secret.py +7 -5
  42. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/setup/default_setup.py +189 -46
  43. digitalkin-1.0.5.dev5/src/digitalkin/services/setup/grpc_setup.py +604 -0
  44. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/setup/setup_strategy.py +89 -18
  45. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/storage/default_storage.py +2 -5
  46. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/storage/grpc_storage.py +112 -62
  47. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/storage/storage_strategy.py +18 -16
  48. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/user_profile/default_user_profile.py +9 -3
  49. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/user_profile/grpc_user_profile.py +18 -12
  50. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/user_profile/user_profile_strategy.py +7 -3
  51. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/setup_content_validator.py +24 -0
  52. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin.egg-info/PKG-INFO +2 -2
  53. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin.egg-info/SOURCES.txt +1 -1
  54. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin.egg-info/requires.txt +1 -1
  55. digitalkin-1.0.5.dev3/src/digitalkin/services/registry/registry_models.py +0 -15
  56. digitalkin-1.0.5.dev3/src/digitalkin/services/setup/grpc_setup.py +0 -406
  57. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/LICENSE +0 -0
  58. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/README.md +0 -0
  59. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/__init__.py +0 -0
  60. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/mock/__init__.py +0 -0
  61. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/mock/mock_pb2.py +0 -0
  62. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  63. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/server_async_insecure.py +0 -0
  64. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/server_async_secure.py +0 -0
  65. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/server_sync_insecure.py +0 -0
  66. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/base_server/server_sync_secure.py +0 -0
  67. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/__init__.py +0 -0
  68. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/echo_module.py +0 -0
  69. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/models/__init__.py +0 -0
  70. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/models/input.py +0 -0
  71. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/models/output.py +0 -0
  72. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/models/secret.py +0 -0
  73. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/models/setup.py +0 -0
  74. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/server.py +0 -0
  75. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/triggers/__init__.py +0 -0
  76. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/bench_module/triggers/message_trigger.py +0 -0
  77. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/__init__.py +0 -0
  78. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/archetype_with_tools_module.py +0 -0
  79. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/cpu_intensive_module.py +0 -0
  80. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/dynamic_setup_module.py +0 -0
  81. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/minimal_llm_module.py +0 -0
  82. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/modules/text_transform_module.py +0 -0
  83. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  84. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  85. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  86. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  87. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  88. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/monitoring/tests/test_metrics.py +0 -0
  89. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/echo_module.py +0 -0
  90. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/models/__init__.py +0 -0
  91. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/models/input.py +0 -0
  92. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/models/output.py +0 -0
  93. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/models/secret.py +0 -0
  94. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/models/setup.py +0 -0
  95. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/server.py +0 -0
  96. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/triggers/__init__.py +0 -0
  97. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/redis_demo/triggers/message_trigger.py +0 -0
  98. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/services/filesystem_module.py +0 -0
  99. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/examples/services/storage_module.py +0 -0
  100. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/setup.cfg +0 -0
  101. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/__init__.py +0 -0
  102. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/__init__.py +0 -0
  103. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/__init__.py +0 -0
  104. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/agui_tools.py +0 -0
  105. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/models.py +0 -0
  106. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/__init__.py +0 -0
  107. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/base.py +0 -0
  108. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
  109. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/defaults.py +0 -0
  110. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
  111. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
  112. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
  113. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
  114. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
  115. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +0 -0
  116. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +0 -0
  117. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
  118. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
  119. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
  120. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
  121. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
  122. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/__init__.py +0 -0
  123. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/common/__init__.py +0 -0
  124. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/common/factories.py +0 -0
  125. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/exceptions.py +0 -0
  126. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/job_manager/__init__.py +0 -0
  127. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  128. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  129. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/profiling/__init__.py +0 -0
  130. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/profiling/step_timer.py +0 -0
  131. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/profiling/task_profiler.py +0 -0
  132. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/resilience/__init__.py +0 -0
  133. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  134. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  135. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/__init__.py +0 -0
  136. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  137. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  138. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  139. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
  140. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
  141. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  142. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  143. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  144. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/core/task_manager/task_session.py +0 -0
  145. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/exceptions.py +0 -0
  146. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/__init__.py +0 -0
  147. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  148. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  149. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  150. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
  151. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
  152. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
  153. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  154. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  155. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  156. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  157. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  158. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
  159. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/logger.py +0 -0
  160. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/__init__.py +0 -0
  161. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/base_mixin.py +0 -0
  162. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/cost_mixin.py +0 -0
  163. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  164. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  165. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/logger_mixin.py +0 -0
  166. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/mixins/storage_mixin.py +0 -0
  167. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/__init__.py +0 -0
  168. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/core/__init__.py +0 -0
  169. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/core/job_manager_models.py +0 -0
  170. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/core/redis.py +0 -0
  171. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/core/task_monitor.py +0 -0
  172. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/events/__init__.py +0 -0
  173. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/events/agent_events.py +0 -0
  174. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  175. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  176. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  177. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/models.py +0 -0
  178. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
  179. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/grpc_servers/types.py +0 -0
  180. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/__init__.py +0 -0
  181. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/ag_ui.py +0 -0
  182. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/base_types.py +0 -0
  183. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/knowledge_files.py +0 -0
  184. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/loaded_tools.py +0 -0
  185. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/module.py +0 -0
  186. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/module_types.py +0 -0
  187. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/request_metadata.py +0 -0
  188. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/select_schema.py +0 -0
  189. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/setup_types.py +0 -0
  190. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/module/tool_reference.py +0 -0
  191. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/__init__.py +0 -0
  192. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/cost.py +0 -0
  193. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/filesystem.py +0 -0
  194. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/services.py +0 -0
  195. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/services/storage.py +0 -0
  196. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/__init__.py +0 -0
  197. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/certificate.py +0 -0
  198. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/client/__init__.py +0 -0
  199. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/client/channel.py +0 -0
  200. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/client/circuit_breaker.py +0 -0
  201. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/client/client.py +0 -0
  202. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/client/grpc.py +0 -0
  203. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/log.py +0 -0
  204. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/profiling.py +0 -0
  205. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/queue.py +0 -0
  206. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/redis.py +0 -0
  207. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/registry.py +0 -0
  208. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/resilience.py +0 -0
  209. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/server/__init__.py +0 -0
  210. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/server/channel.py +0 -0
  211. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/server/grpc.py +0 -0
  212. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/server/server.py +0 -0
  213. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/server/servicer.py +0 -0
  214. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/task_manager.py +0 -0
  215. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  216. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/settings/utils/channel.py +0 -0
  217. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/utils/__init__.py +0 -0
  218. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  219. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/__init__.py +0 -0
  220. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/archetype_module.py +0 -0
  221. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/tool_module.py +0 -0
  222. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/trigger_handler.py +0 -0
  223. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/triggers/__init__.py +0 -0
  224. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  225. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  226. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  227. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/py.typed +0 -0
  228. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/__init__.py +0 -0
  229. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/base_strategy.py +0 -0
  230. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/communication/__init__.py +0 -0
  231. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/cost/__init__.py +0 -0
  232. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/cost/exceptions.py +0 -0
  233. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/filesystem/__init__.py +0 -0
  234. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  235. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  236. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/identity/__init__.py +0 -0
  237. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/identity/default_identity.py +0 -0
  238. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  239. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/registry/exceptions.py +0 -0
  240. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/secret/__init__.py +0 -0
  241. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/secret/default_secret.py +0 -0
  242. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/secret/exceptions.py +0 -0
  243. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/secret/secret_strategy.py +0 -0
  244. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/services_config.py +0 -0
  245. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/services_models.py +0 -0
  246. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/setup/__init__.py +0 -0
  247. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/setup/exceptions.py +0 -0
  248. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/storage/__init__.py +0 -0
  249. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/storage/exceptions.py +0 -0
  250. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/task_manager/__init__.py +0 -0
  251. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
  252. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  253. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  254. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  255. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/user_profile/__init__.py +0 -0
  256. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  257. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/__init__.py +0 -0
  258. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/arg_parser.py +0 -0
  259. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/conditional_schema.py +0 -0
  260. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/development_mode_action.py +0 -0
  261. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/dynamic_schema.py +0 -0
  262. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/env_manager.py +0 -0
  263. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/env_template.py +0 -0
  264. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/exceptions.py +0 -0
  265. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/json_structure.py +0 -0
  266. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  267. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/package_discover.py +0 -0
  268. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/proto_utils.py +0 -0
  269. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin/utils/schema_splitter.py +0 -0
  270. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  271. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/src/digitalkin.egg-info/top_level.txt +0 -0
  272. {digitalkin-1.0.5.dev3 → digitalkin-1.0.5.dev5}/tests/test_exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.5.dev3
3
+ Version: 1.0.5.dev5
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.2
456
+ Requires-Dist: agentic-mesh-protocol==1.2.0
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
@@ -2,11 +2,10 @@
2
2
  """Demo client for the Gateway gRPC service with per-endpoint testing.
3
3
 
4
4
  Subcommands:
5
- full Full pipeline: StartStream → ConsumeStream → SendSignal
5
+ full Full pipeline: StartStream → Stream → SendSignal
6
6
  start StartStream only (unary)
7
- consume ConsumeStream on existing task (requires --task-id)
8
- produce StartStream + ProduceStream (act as Module A)
9
- signal SendSignal on existing task (requires --task-id)
7
+ consume Stream on existing task (requires --task-id)
8
+ signal SendSignal(cancel) on existing task (requires --task-id)
10
9
  inspect Dump Redis keys for a task (no gRPC)
11
10
 
12
11
  Usage:
@@ -14,8 +13,7 @@ Usage:
14
13
  python client.py full --prompt "Test" --setup '{"uppercase": true, "repeat": 5}'
15
14
  python client.py start --prompt "Hello"
16
15
  python client.py consume --task-id <uuid>
17
- python client.py produce --task-id <uuid> --chunks 3
18
- python client.py signal --task-id <uuid> --action cancel
16
+ python client.py signal --task-id <uuid>
19
17
  python client.py inspect --task-id <uuid>
20
18
  """
21
19
 
@@ -34,7 +32,7 @@ import grpc
34
32
  import redis.asyncio as aioredis
35
33
  from google.protobuf import json_format, struct_pb2
36
34
 
37
- from agentic_mesh_protocol.gateway.v1 import gateway_pb2, gateway_service_pb2_grpc
35
+ from agentic_mesh_protocol.gateway.v1 import gateway_dto_pb2, gateway_messages_pb2, gateway_service_pb2_grpc
38
36
 
39
37
  # ── ANSI colors ─────────────────────────────────────────────────────
40
38
 
@@ -291,29 +289,18 @@ def _print_diff_report(tracker: RedisTracker, task_id: str) -> None:
291
289
  async def cmd_start(
292
290
  stub: gateway_service_pb2_grpc.GatewayServiceStub,
293
291
  task_id: str,
294
- prompt: str,
295
- setup: dict[str, Any] | None,
296
292
  ) -> bool:
297
293
  """StartStream — create a task session.
298
294
 
299
295
  Returns:
300
296
  True if accepted.
301
297
  """
302
- input_struct = struct_pb2.Struct()
303
- payload: dict[str, Any] = {
304
- "root": {"protocol": "message", "text": prompt},
305
- }
306
- if setup:
307
- payload["setup"] = setup
308
- input_struct.update(payload)
309
-
310
298
  t0 = time.monotonic()
311
299
  resp = await stub.StartStream(
312
- gateway_pb2.StartStreamRequest(
300
+ gateway_dto_pb2.StartStreamRequest(
313
301
  task_id=task_id,
314
- input=input_struct,
315
- setup_id="demo-setup",
316
- mission_id="demo-mission",
302
+ setup_id="setups:demo",
303
+ mission_id="missions:demo",
317
304
  ),
318
305
  )
319
306
  elapsed = (time.monotonic() - t0) * 1000
@@ -327,112 +314,58 @@ async def cmd_start(
327
314
  async def cmd_consume(
328
315
  stub: gateway_service_pb2_grpc.GatewayServiceStub,
329
316
  task_id: str,
317
+ prompt: str,
318
+ setup: dict[str, Any] | None,
330
319
  verbose: bool,
331
320
  ) -> list[dict[str, Any]]:
332
- """ConsumeStream — read module output from Redis.
321
+ """Stream — send the query, then read module output until ``stream.end``.
333
322
 
334
323
  Returns:
335
324
  List of received items.
336
325
  """
337
326
  received: list[dict[str, Any]] = []
327
+ query: dict[str, Any] = {"root": {"protocol": "message", "text": prompt}}
328
+ if setup:
329
+ query["setup"] = setup
330
+ query_struct = struct_pb2.Struct()
331
+ query_struct.update(query)
338
332
 
339
333
  async def _requests() -> AsyncGenerator:
340
- yield gateway_pb2.ConsumeStreamRequest(
341
- init=gateway_pb2.ConsumeStreamInit(task_id=task_id, from_seq=0),
342
- )
334
+ yield gateway_messages_pb2.StreamRequest(task_id=task_id, from_seq=0, data=query_struct)
343
335
 
344
336
  t0 = time.monotonic()
345
- resp_stream = stub.ConsumeStream(_requests())
346
- async for resp in resp_stream:
347
- elapsed = (time.monotonic() - t0) * 1000
348
- payload_type = resp.WhichOneof("payload")
349
-
350
- if payload_type == "output":
351
- data_dict = json_format.MessageToDict(resp.output.data)
352
- text = data_dict.get("root", {}).get("text", data_dict.get("root", {}).get("protocol", ""))
353
- received.append({"seq": resp.output.seq, "text": text})
354
- print(f" {GREEN}seq={resp.output.seq:>2}{RESET} {text}") # noqa: T201
355
- if verbose:
356
- print(f" {DIM}{json.dumps(data_dict, ensure_ascii=False)}{RESET}") # noqa: T201
357
-
358
- elif payload_type == "status":
359
- state_name = gateway_pb2.StreamState.Name(resp.status.state)
360
- received.append({"status": state_name})
361
- color = GREEN if "COMPLETED" in state_name else YELLOW
362
- print(f" {color}status: {state_name}{RESET} ({elapsed:.1f}ms total)") # noqa: T201
363
- break
364
-
365
- elif payload_type == "error":
366
- received.append({"error": resp.error.message})
367
- print(f" {RED}error: code={resp.error.code} msg={resp.error.message}{RESET}") # noqa: T201
337
+ async for resp in stub.Stream(_requests()):
338
+ root = json_format.MessageToDict(resp.data).get("root", {})
339
+ protocol = root.get("protocol", "")
340
+ if protocol == "stream.error":
341
+ received.append({"seq": resp.seq, "error": root.get("message", "")})
342
+ print(f" {RED}error: code={root.get('code')} msg={root.get('message')}{RESET}") # noqa: T201
343
+ continue
344
+ if protocol == "stream.end":
345
+ received.append({"seq": resp.seq, "status": "stream.end"})
346
+ print(f" {GREEN}stream.end{RESET} ({(time.monotonic() - t0) * 1000:.1f}ms total)") # noqa: T201
368
347
  break
369
-
370
- elif payload_type == "heartbeat":
371
- if verbose:
372
- print(f" {DIM}heartbeat{RESET}") # noqa: T201
348
+ text = root.get("text", protocol)
349
+ received.append({"seq": resp.seq, "text": text})
350
+ print(f" {GREEN}seq={resp.seq:>2}{RESET} {text}") # noqa: T201
351
+ if verbose:
352
+ print(f" {DIM}{json.dumps(root, ensure_ascii=False)}{RESET}") # noqa: T201
373
353
 
374
354
  return received
375
355
 
376
356
 
377
- async def cmd_produce(
378
- stub: gateway_service_pb2_grpc.GatewayServiceStub,
379
- task_id: str,
380
- prompt: str,
381
- num_chunks: int,
382
- ) -> int:
383
- """ProduceStream — act as Module A, push output chunks.
384
-
385
- Returns:
386
- Number of server responses.
387
- """
388
- async def _requests() -> AsyncGenerator:
389
- yield gateway_pb2.ProduceStreamRequest(
390
- init=gateway_pb2.ProduceStreamInit(task_id=task_id),
391
- )
392
- for i in range(num_chunks):
393
- data = struct_pb2.Struct()
394
- data.update({
395
- "root": {
396
- "protocol": "message",
397
- "text": f"[{i + 1}/{num_chunks}] {prompt}",
398
- },
399
- })
400
- yield gateway_pb2.ProduceStreamRequest(
401
- output=gateway_pb2.ProduceStreamOutput(task_id=task_id, data=data),
402
- )
403
- await asyncio.sleep(0.05)
404
-
405
- t0 = time.monotonic()
406
- resp_stream = stub.ProduceStream(_requests())
407
- count = 0
408
- async for resp in resp_stream:
409
- count += 1
410
- payload = resp.WhichOneof("payload")
411
- print(f" response #{count}: {payload}") # noqa: T201
412
-
413
- elapsed = (time.monotonic() - t0) * 1000
414
- print(f" {DIM}stream closed ({count} responses, {elapsed:.1f}ms){RESET}") # noqa: T201
415
- return count
416
-
417
-
418
357
  async def cmd_signal(
419
358
  stub: gateway_service_pb2_grpc.GatewayServiceStub,
420
359
  task_id: str,
421
- action: str,
422
360
  ) -> bool:
423
- """SendSignal — send a control signal.
361
+ """SendSignal — cancel a running task.
424
362
 
425
363
  Returns:
426
364
  True if accepted.
427
365
  """
428
- action_enum = (
429
- gateway_pb2.SIGNAL_ACTION_CANCEL if action == "cancel"
430
- else gateway_pb2.SIGNAL_ACTION_PAUSE
431
- )
432
-
433
366
  t0 = time.monotonic()
434
367
  resp = await stub.SendSignal(
435
- gateway_pb2.ClientSignalRequest(task_id=task_id, action=action_enum),
368
+ gateway_dto_pb2.SendSignalRequest(cancel=gateway_messages_pb2.CancelSignal(task_id=task_id)),
436
369
  )
437
370
  elapsed = (time.monotonic() - t0) * 1000
438
371
 
@@ -447,7 +380,7 @@ async def cmd_signal(
447
380
 
448
381
 
449
382
  async def run_full(args: argparse.Namespace) -> None:
450
- """Full pipeline: StartStream → ConsumeStream → SendSignal."""
383
+ """Full pipeline: StartStream → Stream → SendSignal."""
451
384
  task_id = args.task_id or str(uuid.uuid4())
452
385
  setup = json.loads(args.setup) if args.setup else None
453
386
  tracker = RedisTracker(args.redis) if args.verbose else None
@@ -467,7 +400,7 @@ async def run_full(args: argparse.Namespace) -> None:
467
400
 
468
401
  # 1. StartStream
469
402
  print(f"\n{BOLD}[1] StartStream{RESET}") # noqa: T201
470
- accepted = await cmd_start(stub, task_id, args.prompt, setup)
403
+ accepted = await cmd_start(stub, task_id)
471
404
  if not accepted:
472
405
  print(f" {RED}Server rejected the task — aborting.{RESET}") # noqa: T201
473
406
  return
@@ -476,18 +409,17 @@ async def run_full(args: argparse.Namespace) -> None:
476
409
  await asyncio.sleep(0.1)
477
410
  await tracker.snapshot("StartStream", task_id)
478
411
 
479
- # 2. ConsumeStream — wait for module output
480
- print(f"\n{BOLD}[2] ConsumeStream{RESET}") # noqa: T201
481
- await asyncio.sleep(0.2) # let module start
482
- received = await cmd_consume(stub, task_id, args.verbose)
412
+ # 2. Stream — send the query, read module output
413
+ print(f"\n{BOLD}[2] Stream{RESET}") # noqa: T201
414
+ received = await cmd_consume(stub, task_id, args.prompt, setup, args.verbose)
483
415
 
484
416
  if tracker:
485
417
  await asyncio.sleep(0.1)
486
- await tracker.snapshot("ConsumeStream", task_id)
418
+ await tracker.snapshot("Stream", task_id)
487
419
 
488
420
  # 3. SendSignal
489
421
  print(f"\n{BOLD}[3] SendSignal (cancel){RESET}") # noqa: T201
490
- await cmd_signal(stub, task_id, "cancel")
422
+ await cmd_signal(stub, task_id)
491
423
 
492
424
  if tracker:
493
425
  await asyncio.sleep(0.1)
@@ -513,61 +445,39 @@ async def run_full(args: argparse.Namespace) -> None:
513
445
  async def run_start(args: argparse.Namespace) -> None:
514
446
  """StartStream only."""
515
447
  task_id = args.task_id or str(uuid.uuid4())
516
- setup = json.loads(args.setup) if args.setup else None
517
448
 
518
449
  print(f"\n{BOLD}[StartStream]{RESET} gateway={args.gateway} task_id={task_id}") # noqa: T201
519
450
 
520
451
  async with grpc.aio.insecure_channel(args.gateway, options=GRPC_OPTIONS) as channel:
521
452
  stub = gateway_service_pb2_grpc.GatewayServiceStub(channel)
522
- await cmd_start(stub, task_id, args.prompt, setup)
453
+ await cmd_start(stub, task_id)
523
454
 
524
455
 
525
456
  async def run_consume(args: argparse.Namespace) -> None:
526
- """ConsumeStream on existing task."""
457
+ """Stream on existing task."""
527
458
  if not args.task_id:
528
459
  print(f"{RED}--task-id is required for consume{RESET}") # noqa: T201
529
460
  sys.exit(1)
530
461
 
531
- print(f"\n{BOLD}[ConsumeStream]{RESET} gateway={args.gateway} task_id={args.task_id}") # noqa: T201
532
-
533
- async with grpc.aio.insecure_channel(args.gateway, options=GRPC_OPTIONS) as channel:
534
- stub = gateway_service_pb2_grpc.GatewayServiceStub(channel)
535
- await cmd_consume(stub, args.task_id, args.verbose)
536
-
537
-
538
- async def run_produce(args: argparse.Namespace) -> None:
539
- """StartStream + ProduceStream (act as Module A)."""
540
- task_id = args.task_id or str(uuid.uuid4())
541
462
  setup = json.loads(args.setup) if args.setup else None
542
-
543
- print(f"\n{BOLD}[Produce]{RESET} gateway={args.gateway} task_id={task_id}") # noqa: T201
463
+ print(f"\n{BOLD}[Stream]{RESET} gateway={args.gateway} task_id={args.task_id}") # noqa: T201
544
464
 
545
465
  async with grpc.aio.insecure_channel(args.gateway, options=GRPC_OPTIONS) as channel:
546
466
  stub = gateway_service_pb2_grpc.GatewayServiceStub(channel)
547
-
548
- # StartStream first (registers the session)
549
- print(f"\n {BOLD}StartStream{RESET}") # noqa: T201
550
- accepted = await cmd_start(stub, task_id, args.prompt, setup)
551
- if not accepted:
552
- print(f" {RED}Rejected{RESET}") # noqa: T201
553
- return
554
-
555
- # ProduceStream (act as Module A)
556
- print(f"\n {BOLD}ProduceStream ({args.chunks} chunks){RESET}") # noqa: T201
557
- await cmd_produce(stub, task_id, args.prompt, args.chunks)
467
+ await cmd_consume(stub, args.task_id, args.prompt, setup, args.verbose)
558
468
 
559
469
 
560
470
  async def run_signal(args: argparse.Namespace) -> None:
561
- """SendSignal on existing task."""
471
+ """SendSignal(cancel) on existing task."""
562
472
  if not args.task_id:
563
473
  print(f"{RED}--task-id is required for signal{RESET}") # noqa: T201
564
474
  sys.exit(1)
565
475
 
566
- print(f"\n{BOLD}[SendSignal]{RESET} gateway={args.gateway} task_id={args.task_id} action={args.action}") # noqa: T201
476
+ print(f"\n{BOLD}[SendSignal]{RESET} gateway={args.gateway} task_id={args.task_id} signal=cancel") # noqa: T201
567
477
 
568
478
  async with grpc.aio.insecure_channel(args.gateway, options=GRPC_OPTIONS) as channel:
569
479
  stub = gateway_service_pb2_grpc.GatewayServiceStub(channel)
570
- await cmd_signal(stub, args.task_id, args.action)
480
+ await cmd_signal(stub, args.task_id)
571
481
 
572
482
 
573
483
  async def run_inspect(args: argparse.Namespace) -> None:
@@ -613,8 +523,7 @@ examples:
613
523
  %(prog)s full --prompt "Test" --setup '{"uppercase": true, "repeat": 5}'
614
524
  %(prog)s start --prompt "Hello"
615
525
  %(prog)s consume --task-id <uuid>
616
- %(prog)s produce --chunks 5 --prompt "Manual"
617
- %(prog)s signal --task-id <uuid> --action cancel
526
+ %(prog)s signal --task-id <uuid>
618
527
  %(prog)s inspect --task-id <uuid>
619
528
  """,
620
529
  )
@@ -631,21 +540,16 @@ examples:
631
540
  sub = p.add_subparsers(dest="command", help="Endpoint to test")
632
541
 
633
542
  # full (default)
634
- sub.add_parser("full", help="Full pipeline: StartStream -> ConsumeStream -> SendSignal")
543
+ sub.add_parser("full", help="Full pipeline: StartStream -> Stream -> SendSignal")
635
544
 
636
545
  # start
637
546
  sub.add_parser("start", help="StartStream only (unary)")
638
547
 
639
548
  # consume
640
- sub.add_parser("consume", help="ConsumeStream on existing task (requires --task-id)")
641
-
642
- # produce
643
- sp_produce = sub.add_parser("produce", help="StartStream + ProduceStream (act as Module A)")
644
- sp_produce.add_argument("--chunks", type=int, default=3, help="Number of chunks to produce (default: 3)")
549
+ sub.add_parser("consume", help="Stream on existing task (requires --task-id)")
645
550
 
646
551
  # signal
647
- sp_signal = sub.add_parser("signal", help="SendSignal on existing task (requires --task-id)")
648
- sp_signal.add_argument("--action", choices=["cancel", "pause"], default="cancel", help="Signal action (default: cancel)")
552
+ sub.add_parser("signal", help="SendSignal(cancel) on existing task (requires --task-id)")
649
553
 
650
554
  # inspect
651
555
  sub.add_parser("inspect", help="Dump Redis keys for a task (no gRPC)")
@@ -662,17 +566,10 @@ async def main() -> None:
662
566
  if not args.command:
663
567
  args.command = "full"
664
568
 
665
- # Set defaults for subcommand-specific args
666
- if not hasattr(args, "chunks"):
667
- args.chunks = 3
668
- if not hasattr(args, "action"):
669
- args.action = "cancel"
670
-
671
569
  handlers = {
672
570
  "full": run_full,
673
571
  "start": run_start,
674
572
  "consume": run_consume,
675
- "produce": run_produce,
676
573
  "signal": run_signal,
677
574
  "inspect": run_inspect,
678
575
  }
@@ -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.2",
34
+ "agentic-mesh-protocol==1.2.0",
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.5.dev3"
44
+ version = "1.0.5.dev5"
45
45
 
46
46
  [project.optional-dependencies]
47
47
  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.5.dev3"
8
+ __version__ = "1.0.5.dev5"
@@ -676,6 +676,26 @@ class AgnoStreamAdapter:
676
676
  self._closed_tool_call_ids.add(tool_call_id)
677
677
 
678
678
  content = agno_event.content
679
+ if tool is not None and tool.tool_call_error:
680
+ # Agno flags a raised tool on the completed event, then sends a tool_call_error
681
+ # that the closed-id check drops — so the failure is surfaced here.
682
+ # TODO(validate): AGUI-TOOL-FAILED-STATUS a raised tool surfaces as ToolCallError, not success
683
+ logger.info(
684
+ "[VALIDATE AGUI-TOOL-FAILED-STATUS] tool %s (id=%s) failed: %s",
685
+ tool.tool_name,
686
+ tool_call_id,
687
+ tool.result,
688
+ )
689
+ return [
690
+ ToolCallErrorEvent(
691
+ event=AgentRunEvent.TOOL_CALL_ERROR,
692
+ tool=tool_info,
693
+ error_message=str(tool.result) if tool.result else None,
694
+ subagent_run_id=self._subagent_of(self._run_key),
695
+ timestamp=timestamp,
696
+ metadata=self._last_metadata,
697
+ )
698
+ ]
679
699
  return [
680
700
  ToolCallCompletedEvent(
681
701
  event=AgentRunEvent.TOOL_CALL_COMPLETED,
@@ -11,6 +11,7 @@ import json
11
11
  import logging
12
12
  from typing import TYPE_CHECKING, Any, ClassVar
13
13
 
14
+ from ag_ui.core.events import Interrupt, RunFinishedInterruptOutcome
14
15
  from pydantic import BaseModel, ConfigDict, Field
15
16
 
16
17
  from digitalkin.community.agno.models import PauseInfo
@@ -268,13 +269,14 @@ class HitlEvents:
268
269
  run_id: str,
269
270
  pending_tool_call_ids: list[str],
270
271
  ) -> None:
271
- """Emit an AG-UI ``RunFinished`` with ``status="awaiting_tool_result"``.
272
+ """Emit an AG-UI ``RunFinished`` with an interrupt outcome.
272
273
 
273
274
  This is the protocol signal telling the front "the run paused on a
274
- client-side tool; execute it and reply with a ``ToolMessage``". It
275
- goes out via ``context.callbacks.send_message`` (bypassing the
276
- standard :class:`~digitalkin.mixins.agui_mixin.AgUiMixin` event
277
- mapping, which has no notion of an "awaiting" status).
275
+ client-side tool; execute it and reply with a ``ToolMessage``". The
276
+ standard ``outcome={type: "interrupt"}`` carries one interrupt per pending
277
+ tool; the legacy ``result.status="awaiting_tool_result"`` is kept for
278
+ existing clients. When an AG-UI run is open, its state first moves the
279
+ tools to ``awaiting_input`` and the run to ``interrupted``.
278
280
 
279
281
  Args:
280
282
  context: Current module context.
@@ -291,11 +293,31 @@ class HitlEvents:
291
293
  AgUiRunFinishedOutput,
292
294
  )
293
295
 
296
+ run = context.agui_run
297
+ tools = run.state["tools"] if run is not None else {}
298
+ interrupts = [
299
+ Interrupt(
300
+ id=tool_call_id,
301
+ reason="tool_call",
302
+ tool_call_id=tool_call_id,
303
+ message=f"Waiting for the result of {tools.get(tool_call_id, {}).get('name') or 'a frontend tool'}",
304
+ )
305
+ for tool_call_id in pending_tool_call_ids
306
+ ]
307
+ if run is not None and run.open:
308
+ run.open = False
309
+ await run.update(
310
+ context,
311
+ *((("tools", tid, "status"), "awaiting_input") for tid in pending_tool_call_ids if tid in tools),
312
+ (("interrupts",), [i.model_dump(mode="json", by_alias=True, exclude_none=True) for i in interrupts]),
313
+ (("run", "status"), "interrupted"),
314
+ )
294
315
  output = AgUiOutput(
295
316
  root=AgUiRunFinishedOutput(
296
317
  event=AgUiRunFinishedEvent(
297
318
  thread_id=thread_id,
298
319
  run_id=run_id,
320
+ outcome=RunFinishedInterruptOutcome(interrupts=interrupts) if interrupts else None,
299
321
  result={
300
322
  "status": _AWAITING_STATUS,
301
323
  "pending_tool_call_ids": pending_tool_call_ids,
@@ -25,6 +25,7 @@ from digitalkin.logger import logger
25
25
  from digitalkin.models.module import ModuleContext
26
26
  from digitalkin.models.module.ag_ui import AgUiCustomEventOutput, AgUiOutput
27
27
  from digitalkin.models.module.tool_cache import ToolDefinition, ToolModuleInfo
28
+ from digitalkin.services.communication.exceptions import ToolCallError
28
29
 
29
30
  # Default timeout for tool calls in seconds
30
31
  DEFAULT_TOOL_TIMEOUT_SECONDS = 300
@@ -265,7 +266,14 @@ class ModuleToolkit(DkToolkit):
265
266
  # callbacks is a dict-driven SimpleNamespace (module_context.py:168);
266
267
  # send_message may legitimately be absent outside a running job.
267
268
  send_message = vars(context.callbacks).get("send_message")
269
+ value = event.get("value")
270
+ url = value.get("url") if isinstance(value, dict) else None
268
271
  if send_message is None:
272
+ logger.warning(
273
+ "Dropped custom event '%s' url=%s: no send_message on the agent context",
274
+ event["name"],
275
+ url,
276
+ )
269
277
  return
270
278
 
271
279
  try:
@@ -275,10 +283,15 @@ class ModuleToolkit(DkToolkit):
275
283
  await send_message(
276
284
  AgUiOutput(
277
285
  root=AgUiCustomEventOutput(
278
- event=AgUiCustomEvent(name=event["name"], value=event.get("value")),
286
+ event=AgUiCustomEvent(name=event["name"], value=value),
279
287
  )
280
288
  )
281
289
  )
290
+ logger.info(
291
+ "Relayed custom event '%s' url=%s to the agent stream",
292
+ event["name"],
293
+ url,
294
+ )
282
295
  except Exception:
283
296
  logger.exception("Failed to relay custom event '%s' to the agent stream", event["name"])
284
297
 
@@ -467,6 +480,10 @@ class ModuleToolkit(DkToolkit):
467
480
  Wraps the SDK module's async generator function into an async function
468
481
  that Agno can consume, with proper error handling and response formatting.
469
482
 
483
+ A failure raises ``ToolCallError`` carrying the same JSON body a success-path caller
484
+ would have read: Agno hands ``str(exc)`` to the model unchanged and flags the call
485
+ ``tool_call_error``, which is what marks the tool failed for the front.
486
+
470
487
  Returns:
471
488
  Async function that calls the SDK tool and returns a JSON result, or a
472
489
  ToolResult when the tool returned images alongside its text output.
@@ -509,14 +526,14 @@ class ModuleToolkit(DkToolkit):
509
526
  duration_ms = round((time.perf_counter() - start_time) * 1000, 2)
510
527
  error_msg = f"Tool '{tool_name}' timed out after {timeout}s"
511
528
  logger.warning("%s task_id=%s", error_msg, task_id)
512
- return handle_failure(tool_name, error_msg, duration_ms)
529
+ raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
513
530
 
514
531
  except Exception as e:
515
532
  outcome = "error"
516
533
  duration_ms = round((time.perf_counter() - start_time) * 1000, 2)
517
534
  error_msg = f"Failed to call tool '{tool_name}': {e!s}"
518
535
  logger.warning("%s task_id=%s", error_msg, task_id, exc_info=True)
519
- return handle_failure(tool_name, error_msg, duration_ms)
536
+ raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
520
537
 
521
538
  else:
522
539
  call_timer.mark("gen_consume")
@@ -536,7 +553,7 @@ class ModuleToolkit(DkToolkit):
536
553
 
537
554
  outcome = "no_success"
538
555
  error_msg = ModuleToolkit._extract_error_message(error_frame)
539
- return handle_failure(tool_name, error_msg, duration_ms)
556
+ raise ToolCallError(handle_failure(tool_name, error_msg, duration_ms))
540
557
 
541
558
  finally:
542
559
  call_timer.mark("respond")
@@ -16,6 +16,7 @@ from pydantic import Field
16
16
  from digitalkin.community.agno.toolkits.registry.base import RegistryAction
17
17
  from digitalkin.logger import logger
18
18
  from digitalkin.models.services.registry import (
19
+ RegistryModuleType,
19
20
  RegistrySetupStatus,
20
21
  RegistrySortBy,
21
22
  RegistryVisibility,
@@ -36,7 +37,7 @@ class GetAction(RegistryAction):
36
37
  """Read the setup (always its current version), refusing a foreign object type.
37
38
 
38
39
  Returns:
39
- The setup with its current version, status and visibility.
40
+ The setup with its current version, status and visibility, and a service's key map.
40
41
  """
41
42
  return await ctx.ensure_kind(self.setup_id)
42
43
 
@@ -55,7 +56,6 @@ class SearchAction(RegistryAction):
55
56
  this manager's own kind. Filters combine with AND; within one filter the values are OR'd.
56
57
  """
57
58
 
58
- _DOC_PREVIEW_CHARS: ClassVar[int] = 300
59
59
  # The service ceiling itself (storage and registry both cap a page at 100), so the toolkit
60
60
  # no longer imposes a tighter one of its own.
61
61
  _MAX_RESULTS: ClassVar[int] = 100
@@ -125,14 +125,16 @@ class SearchAction(RegistryAction):
125
125
  # would both contradict ``total_returned`` and, at exactly ``cap`` rows, promise an empty
126
126
  # next page.
127
127
  truncated = len(usable) > cap
128
- rows = [self._row(setup) for setup in usable[:cap]]
128
+ rows = [self._row(setup, ctx.module_type) for setup in usable[:cap]]
129
129
  return {"total_returned": len(rows), "truncated": truncated, "offset": self.offset, "setups": rows}
130
130
 
131
- def _row(self, setup: SetupSummary) -> dict[str, Any]:
131
+ @staticmethod
132
+ def _row(setup: SetupSummary, module_type: RegistryModuleType) -> dict[str, Any]:
132
133
  """Trim one search hit to the fields a caller can act on.
133
134
 
134
135
  Args:
135
136
  setup: The summary returned by the registry.
137
+ module_type: The manager's object type; only services render a structure map.
136
138
 
137
139
  Returns:
138
140
  The rendered row.
@@ -147,11 +149,16 @@ class SearchAction(RegistryAction):
147
149
  "tags": setup.tags,
148
150
  "visibility": setup.visibility.value if setup.visibility else None,
149
151
  "status": setup.status.value if setup.status else None,
150
- "description": (setup.documentation or "")[: self._DOC_PREVIEW_CHARS],
152
+ "documentation": setup.documentation or None,
151
153
  }
152
- # Only service setups carry a map. Omitting the key rather than rendering an empty
153
- # one keeps the feature out of the tools and kins surfaces entirely.
154
- if setup.structure:
154
+ # Only service setups carry a map, so tools and kins rows never show one. A service row
155
+ # always does, {} included: a caller iterating rows must not meet a missing key.
156
+ if module_type == RegistryModuleType.SERVICE:
157
+ if not setup.structure:
158
+ logger.info(
159
+ "[VALIDATE STRUCTROW] service row rendered with an empty structure: setup_id=%s",
160
+ setup.setup_id,
161
+ ) # TODO(validate): remove after prod validation
155
162
  row["structure"] = setup.structure
156
163
  return row
157
164
 
@@ -182,9 +189,10 @@ class UpdateAction(RegistryAction):
182
189
  )
183
190
  documentation: str | None = Field(
184
191
  default=None,
185
- description="Free text describing what this instance is for, indexed by ``search``. "
186
- "Omit to keep the text the instance already has; pass a string to replace it, or an "
187
- "empty string to clear it.",
192
+ max_length=300,
193
+ description="Free text describing what this instance is for, indexed by ``search``, at "
194
+ "most 300 characters. Omit to keep the text the instance already has; pass a string to "
195
+ "replace it, or an empty string to clear it.",
188
196
  )
189
197
 
190
198
  def _type_payload(self) -> dict[str, Any]: # ruff: ignore[no-self-use]