digitalkin 1.0.1.dev0__tar.gz → 1.0.2.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/PKG-INFO +6 -6
  2. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/pyproject.toml +27 -28
  3. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/__init__.py +5 -0
  5. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/module_toolkit.py +3 -3
  6. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/__init__.py +20 -0
  7. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/base.py +91 -0
  8. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/chat_history.py +298 -0
  9. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/defaults.py +57 -0
  10. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/registry.py +166 -0
  11. digitalkin-1.0.2.dev0/src/digitalkin/community/agno/toolkits/user_profile.py +59 -0
  12. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/gateway_servicer.py +14 -8
  13. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/module_server.py +2 -0
  14. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/module_context.py +9 -1
  15. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/services/registry.py +23 -1
  16. digitalkin-1.0.2.dev0/src/digitalkin/models/settings/registry.py +29 -0
  17. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/_base_module.py +26 -1
  18. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/archetype_module.py +2 -0
  19. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/tool_module.py +4 -0
  20. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/communication/exceptions.py +4 -0
  21. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/registry/default_registry.py +97 -12
  22. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/registry/grpc_registry.py +176 -17
  23. digitalkin-1.0.2.dev0/src/digitalkin/services/registry/registry_strategy.py +215 -0
  24. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/storage/grpc_storage.py +28 -1
  25. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin.egg-info/PKG-INFO +6 -6
  26. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin.egg-info/SOURCES.txt +7 -0
  27. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin.egg-info/requires.txt +5 -5
  28. digitalkin-1.0.1.dev0/src/digitalkin/services/registry/registry_strategy.py +0 -128
  29. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/LICENSE +0 -0
  30. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/README.md +0 -0
  31. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/__init__.py +0 -0
  32. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/mock/__init__.py +0 -0
  33. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
  34. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  35. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/server_async_insecure.py +0 -0
  36. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/server_async_secure.py +0 -0
  37. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/server_sync_insecure.py +0 -0
  38. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/base_server/server_sync_secure.py +0 -0
  39. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/__init__.py +0 -0
  40. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/echo_module.py +0 -0
  41. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/models/__init__.py +0 -0
  42. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/models/input.py +0 -0
  43. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/models/output.py +0 -0
  44. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/models/secret.py +0 -0
  45. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/models/setup.py +0 -0
  46. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/server.py +0 -0
  47. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/triggers/__init__.py +0 -0
  48. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/bench_module/triggers/message_trigger.py +0 -0
  49. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/__init__.py +0 -0
  50. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/archetype_with_tools_module.py +0 -0
  51. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/cpu_intensive_module.py +0 -0
  52. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/dynamic_setup_module.py +0 -0
  53. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/minimal_llm_module.py +0 -0
  54. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/modules/text_transform_module.py +0 -0
  55. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  56. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  57. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  58. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  59. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  60. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/monitoring/tests/test_metrics.py +0 -0
  61. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/client.py +0 -0
  62. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/echo_module.py +0 -0
  63. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/models/__init__.py +0 -0
  64. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/models/input.py +0 -0
  65. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/models/output.py +0 -0
  66. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/models/secret.py +0 -0
  67. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/models/setup.py +0 -0
  68. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/server.py +0 -0
  69. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/triggers/__init__.py +0 -0
  70. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/redis_demo/triggers/message_trigger.py +0 -0
  71. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/services/filesystem_module.py +0 -0
  72. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/examples/services/storage_module.py +0 -0
  73. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/setup.cfg +0 -0
  74. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/__init__.py +0 -0
  75. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/__init__.py +0 -0
  76. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/agno_adapter.py +0 -0
  77. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/agui_tools.py +0 -0
  78. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/hitl.py +0 -0
  79. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/community/agno/models.py +0 -0
  80. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/__init__.py +0 -0
  81. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/common/__init__.py +0 -0
  82. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/common/factories.py +0 -0
  83. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/exceptions.py +0 -0
  84. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
  85. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  86. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  87. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/profiling/__init__.py +0 -0
  88. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/profiling/step_timer.py +0 -0
  89. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/profiling/task_profiler.py +0 -0
  90. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/resilience/__init__.py +0 -0
  91. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  92. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  93. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
  94. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  95. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  96. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/module_runner.py +0 -0
  97. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  98. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
  99. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
  100. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  101. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
  102. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/redis/redis_state.py +0 -0
  103. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  104. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  105. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/core/task_manager/task_session.py +0 -0
  106. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/exceptions.py +0 -0
  107. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
  108. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  109. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  110. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  111. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
  112. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
  113. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
  114. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
  115. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
  116. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  117. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  118. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  119. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  120. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  121. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  122. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
  123. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/logger.py +0 -0
  124. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/__init__.py +0 -0
  125. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/agui_mixin.py +0 -0
  126. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
  127. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
  128. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  129. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  130. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
  131. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
  132. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/__init__.py +0 -0
  133. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/core/__init__.py +0 -0
  134. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
  135. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/core/redis.py +0 -0
  136. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
  137. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/events/__init__.py +0 -0
  138. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/events/agent_events.py +0 -0
  139. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  140. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  141. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  142. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/models.py +0 -0
  143. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
  144. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
  145. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/__init__.py +0 -0
  146. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/ag_ui.py +0 -0
  147. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/base_types.py +0 -0
  148. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/module.py +0 -0
  149. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/module_types.py +0 -0
  150. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/request_metadata.py +0 -0
  151. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/select_schema.py +0 -0
  152. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/setup_types.py +0 -0
  153. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/tool_cache.py +0 -0
  154. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/tool_reference.py +0 -0
  155. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/module/utility.py +0 -0
  156. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/services/__init__.py +0 -0
  157. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/services/cost.py +0 -0
  158. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/services/services.py +0 -0
  159. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/services/storage.py +0 -0
  160. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/__init__.py +0 -0
  161. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/gateway.py +0 -0
  162. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/grpc_client.py +0 -0
  163. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/log.py +0 -0
  164. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/module.py +0 -0
  165. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/profiling.py +0 -0
  166. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/queue.py +0 -0
  167. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/redis.py +0 -0
  168. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/resilience.py +0 -0
  169. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/server/__init__.py +0 -0
  170. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/server/channel.py +0 -0
  171. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/server/grpc.py +0 -0
  172. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/server/server.py +0 -0
  173. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/server/servicer.py +0 -0
  174. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/task_manager.py +0 -0
  175. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  176. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/settings/utils/channel.py +0 -0
  177. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/utils/__init__.py +0 -0
  178. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  179. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/__init__.py +0 -0
  180. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/trigger_handler.py +0 -0
  181. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/triggers/__init__.py +0 -0
  182. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  183. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  184. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  185. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/py.typed +0 -0
  186. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/__init__.py +0 -0
  187. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/base_strategy.py +0 -0
  188. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/communication/__init__.py +0 -0
  189. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  190. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/communication/default_communication.py +0 -0
  191. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  192. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
  193. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  194. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
  195. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/cost/exceptions.py +0 -0
  196. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  197. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
  198. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  199. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  200. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  201. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  202. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
  203. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/identity/default_identity.py +0 -0
  204. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  205. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
  206. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/registry/exceptions.py +0 -0
  207. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/registry/registry_models.py +0 -0
  208. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/secret/__init__.py +0 -0
  209. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/secret/default_secret.py +0 -0
  210. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/secret/exceptions.py +0 -0
  211. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/secret/grpc_secret.py +0 -0
  212. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/secret/secret_strategy.py +0 -0
  213. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/services_config.py +0 -0
  214. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/services_models.py +0 -0
  215. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
  216. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/setup/default_setup.py +0 -0
  217. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/setup/exceptions.py +0 -0
  218. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  219. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  220. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
  221. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/storage/default_storage.py +0 -0
  222. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/storage/exceptions.py +0 -0
  223. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  224. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/task_manager/__init__.py +0 -0
  225. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
  226. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  227. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  228. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  229. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/user_profile/__init__.py +0 -0
  230. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  231. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  232. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  233. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  234. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/__init__.py +0 -0
  235. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/arg_parser.py +0 -0
  236. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/conditional_schema.py +0 -0
  237. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/development_mode_action.py +0 -0
  238. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/dynamic_schema.py +0 -0
  239. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/exceptions.py +0 -0
  240. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  241. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/package_discover.py +0 -0
  242. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/proto_utils.py +0 -0
  243. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin/utils/schema_splitter.py +0 -0
  244. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  245. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/src/digitalkin.egg-info/top_level.txt +0 -0
  246. {digitalkin-1.0.1.dev0 → digitalkin-1.0.2.dev0}/tests/test_exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 1.0.1.dev0
3
+ Version: 1.0.2.dev0
4
4
  Summary: SDK to build kin used in DigitalKin
5
5
  Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
6
6
  License: Attribution-NonCommercial-ShareAlike 4.0 International
@@ -453,13 +453,13 @@ 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.0b0
456
+ Requires-Dist: agentic-mesh-protocol==1.0.1.dev2
457
457
  Requires-Dist: anyio>=4.13.0
458
- Requires-Dist: grpcio-health-checking==1.81.0
459
- Requires-Dist: grpcio-reflection==1.81.0
460
- Requires-Dist: grpcio-status==1.81.0
461
- Requires-Dist: pydantic>=2.12.4
458
+ Requires-Dist: grpcio-health-checking==1.82.1
459
+ Requires-Dist: grpcio-reflection==1.82.1
460
+ Requires-Dist: grpcio-status==1.82.1
462
461
  Requires-Dist: pydantic-settings>=2.14.1
462
+ Requires-Dist: pydantic>=2.12.4
463
463
  Requires-Dist: redis[hiredis]<9,>=7.4.0
464
464
  Provides-Extra: agno
465
465
  Requires-Dist: agno>=2.6; extra == "agno"
@@ -28,19 +28,19 @@
28
28
 
29
29
  dependencies = [
30
30
  "ag-ui-protocol>=0.1.18",
31
- "agentic-mesh-protocol==1.0.0b0",
31
+ "agentic-mesh-protocol==1.0.1.dev2",
32
32
  "anyio>=4.13.0",
33
- "grpcio-health-checking==1.81.0",
34
- "grpcio-reflection==1.81.0",
35
- "grpcio-status==1.81.0",
36
- "pydantic>=2.12.4",
33
+ "grpcio-health-checking==1.82.1",
34
+ "grpcio-reflection==1.82.1",
35
+ "grpcio-status==1.82.1",
37
36
  "pydantic-settings>=2.14.1",
37
+ "pydantic>=2.12.4",
38
38
  "redis[hiredis]>=7.4.0,<9",
39
39
  ]
40
- version = "1.0.1.dev0"
40
+ version = "1.0.2.dev0"
41
41
 
42
42
  [project.optional-dependencies]
43
- agno = [ "agno>=2.6" ]
43
+ agno = [ "agno>=2.6" ]
44
44
  performance = [ "uvloop>=0.21" ]
45
45
  profiling = [
46
46
  "pyinstrument>=5.1.2",
@@ -57,6 +57,22 @@
57
57
  name = "DigitalKin.ai"
58
58
 
59
59
  [dependency-groups]
60
+ tests = [
61
+ "fakeredis[lua]>=2.35.1",
62
+ "freezegun>=1.5.5",
63
+ "grpcio-testing>=1.81.0",
64
+ "hdrhistogram>=0.10.3",
65
+ "hypothesis>=6.152.8",
66
+ "objgraph>=3.6",
67
+ "psutil>=7.2.2",
68
+ "pytest-asyncio>=1.3.0",
69
+ "pytest-benchmark>=5.2.3",
70
+ "pytest-cov>=7.1.0",
71
+ "pytest-html>=4.2.0",
72
+ "pytest-json-report>=1.5.0",
73
+ "pytest-timeout>=2.4.0",
74
+ "pytest>=9.0.3",
75
+ ]
60
76
  dev = [
61
77
  "build>=1.5.0",
62
78
  "bump-my-version>=1.3.0",
@@ -68,7 +84,7 @@
68
84
  "twine>=6.2.0",
69
85
  "types-grpcio-health-checking>=1.0.0.20260518",
70
86
  "types-grpcio-reflection>=1.0.0.20260508",
71
- "types-grpcio>=1.0.0.20260518",
87
+ "types-grpcio>=1.82.1.20260711",
72
88
  "types-protobuf>=7.34.1.20260518",
73
89
  "typos>=1.48.0",
74
90
  ]
@@ -96,23 +112,6 @@
96
112
  "mkdocstrings>=1.0.4",
97
113
  "tomli>=2.4.1",
98
114
  ]
99
- tests = [
100
- "agno>=2.6",
101
- "fakeredis[lua]>=2.35.1",
102
- "freezegun>=1.5.5",
103
- "grpcio-testing>=1.81.0",
104
- "hdrhistogram>=0.10.3",
105
- "hypothesis>=6.152.8",
106
- "objgraph>=3.6",
107
- "psutil>=7.2.2",
108
- "pytest-asyncio>=1.3.0",
109
- "pytest-benchmark>=4.0",
110
- "pytest-cov>=7.1.0",
111
- "pytest-html>=4.2.0",
112
- "pytest-json-report>=1.5.0",
113
- "pytest-timeout>=2.4.0",
114
- "pytest>=9.0.3",
115
- ]
116
115
  [tool.setuptools]
117
116
  package-dir = { "" = "src" }
118
117
 
@@ -148,12 +147,12 @@
148
147
  "buck-out",
149
148
  "build",
150
149
  "dist",
151
- "scripts",
152
150
  "docs/*",
153
151
  "examples/*",
154
152
  "factory.py",
155
153
  "generate_certificates.py",
156
154
  "node_modules",
155
+ "scripts",
157
156
  "tests/*",
158
157
  "venv",
159
158
  ]
@@ -270,10 +269,10 @@
270
269
  skip-magic-trailing-comma = false
271
270
 
272
271
  [tool.mypy]
273
- exclude = [ "examples", "tests", "scripts" ]
272
+ exclude = [ "examples", "scripts", "tests" ]
274
273
  ignore_missing_imports = true
275
- warn_unused_ignores = true
276
274
  warn_redundant_casts = true
275
+ warn_unused_ignores = true
277
276
 
278
277
  [tool.pytest.ini_options]
279
278
 
@@ -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.1.dev0"
8
+ __version__ = "1.0.2.dev0"
@@ -20,6 +20,11 @@ optional ``agno`` dependency at import time and is therefore NOT exported here;
20
20
  import it directly::
21
21
 
22
22
  from digitalkin.community.agno.module_toolkit import ModuleToolkit
23
+
24
+ Default agent toolkits (``ChatHistoryTools``, ``UserProfileTools``,
25
+ ``RegistryTools``, ``DefaultToolkits``) live in
26
+ :mod:`digitalkin.community.agno.toolkits` — imported separately because they
27
+ require the optional ``agno`` dependency at import time.
23
28
  """
24
29
 
25
30
  from digitalkin.community.agno.agno_adapter import AgnoStreamAdapter
@@ -16,10 +16,10 @@ from typing import Any
16
16
 
17
17
  from ag_ui.core.events import CustomEvent as AgUiCustomEvent
18
18
  from agno.media import Image
19
- from agno.tools import Toolkit
20
19
  from agno.tools.function import Function, ToolResult
21
20
 
22
21
  from digitalkin.community.agno.models import ToolCallMetadata, ToolOutputMetadata
22
+ from digitalkin.community.agno.toolkits.base import DkToolkit
23
23
  from digitalkin.core.profiling.step_timer import StepTimer
24
24
  from digitalkin.logger import logger
25
25
  from digitalkin.models.module import ModuleContext
@@ -38,7 +38,7 @@ TOOL_CONTENT_PROTOCOL = "tool_content"
38
38
  AGUI_CUSTOM_PROTOCOL = "agui_custom"
39
39
 
40
40
 
41
- class ModuleToolkit(Toolkit):
41
+ class ModuleToolkit(DkToolkit):
42
42
  """Agno Toolkit wrapper for SDK module tools.
43
43
 
44
44
  Wraps a ToolModuleInfo containing multiple ToolDefinitions into
@@ -170,7 +170,7 @@ class ModuleToolkit(Toolkit):
170
170
  or tool_module_info.module_name
171
171
  or tool_module_info.slug.replace(":", "_").replace(".", "_")
172
172
  )
173
- super().__init__(name=f"{toolkit_name}_toolkit", tools=agno_functions)
173
+ super().__init__(name=f"{toolkit_name}_toolkit", tools=agno_functions, context=self._context)
174
174
 
175
175
  @property
176
176
  def module_id(self) -> str:
@@ -0,0 +1,20 @@
1
+ """Default Agno toolkits for DigitalKin modules.
2
+
3
+ Requires the optional ``agno`` dependency — importing this subpackage without
4
+ ``agno`` installed raises ModuleNotFoundError. The parent
5
+ ``digitalkin.community.agno`` package stays importable without agno.
6
+ """
7
+
8
+ from digitalkin.community.agno.toolkits.base import DkToolkit
9
+ from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
10
+ from digitalkin.community.agno.toolkits.defaults import DefaultToolkits
11
+ from digitalkin.community.agno.toolkits.registry import RegistryTools
12
+ from digitalkin.community.agno.toolkits.user_profile import UserProfileTools
13
+
14
+ __all__ = [
15
+ "ChatHistoryTools",
16
+ "DefaultToolkits",
17
+ "DkToolkit",
18
+ "RegistryTools",
19
+ "UserProfileTools",
20
+ ]
@@ -0,0 +1,91 @@
1
+ """Shared base for DigitalKin agno toolkits.
2
+
3
+ Codifies the format/return conventions established by
4
+ :class:`~digitalkin.community.agno.module_toolkit.ModuleToolkit`: a canonical
5
+ ``{"output"|"error", "metadata"}`` JSON envelope (:meth:`_ok`/:meth:`_fail`) and
6
+ best-effort AG-UI custom-event notifications on the agent's own stream
7
+ (:meth:`_notify`). Every toolkit returns consistently and never raises into the
8
+ agent loop.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from ag_ui.core.events import CustomEvent as AgUiCustomEvent
17
+ from agno.tools import Toolkit
18
+
19
+ from digitalkin.logger import logger
20
+ from digitalkin.models.module.ag_ui import AgUiCustomEventOutput, AgUiOutput
21
+
22
+ if TYPE_CHECKING:
23
+ from digitalkin.models.module import ModuleContext
24
+
25
+
26
+ class DkToolkit(Toolkit):
27
+ """Base class for DigitalKin agno toolkits.
28
+
29
+ Subclasses register bound async tool methods and return via :meth:`_ok`/
30
+ :meth:`_fail` so the agent always receives the same envelope and the tool
31
+ never raises. Passing a :class:`ModuleContext` enables :meth:`_notify`,
32
+ which pushes AG-UI custom events onto the caller's gRPC stream.
33
+ """
34
+
35
+ def __init__(self, name: str, tools: list[Any], context: ModuleContext | None = None) -> None:
36
+ """Initialize the toolkit.
37
+
38
+ Args:
39
+ name: Toolkit name registered with Agno.
40
+ tools: Bound tool callables to expose to the agent.
41
+ context: Module context; when present, :meth:`_notify` can emit AG-UI events.
42
+ """
43
+ self._ctx = context
44
+ super().__init__(name=name, tools=tools)
45
+
46
+ @staticmethod
47
+ def _ok(output: Any, **metadata: Any) -> str:
48
+ """Build the canonical success envelope.
49
+
50
+ Args:
51
+ output: The tool result payload (JSON-serializable).
52
+ metadata: Extra metadata fields (e.g. ``tool``).
53
+
54
+ Returns:
55
+ JSON string ``{"output": ..., "metadata": {"success": true, ...}}``.
56
+ """
57
+ return json.dumps({"output": output, "metadata": {"success": True, **metadata}}, ensure_ascii=False)
58
+
59
+ @staticmethod
60
+ def _fail(error: str, **metadata: Any) -> str:
61
+ """Build the canonical error envelope.
62
+
63
+ Args:
64
+ error: Human/LLM-readable error message.
65
+ metadata: Extra metadata fields (e.g. ``tool``).
66
+
67
+ Returns:
68
+ JSON string ``{"error": ..., "metadata": {"success": false, ...}}``.
69
+ """
70
+ return json.dumps({"error": error, "metadata": {"success": False, **metadata}}, ensure_ascii=False)
71
+
72
+ async def _notify(self, name: str, value: Any) -> None:
73
+ """Emit an AG-UI custom event on the agent's output stream (best-effort).
74
+
75
+ No-op when there is no context or ``send_message`` is not installed (e.g. outside a
76
+ running job). Never raises — a notification failure must not fail the tool call.
77
+
78
+ Args:
79
+ name: Custom event name.
80
+ value: Custom event payload (JSON-serializable).
81
+ """
82
+ if self._ctx is None:
83
+ return
84
+ # callbacks is a dict-driven SimpleNamespace; send_message is attached during prepare().
85
+ send_message = vars(self._ctx.callbacks).get("send_message")
86
+ if send_message is None:
87
+ return
88
+ try:
89
+ await send_message(AgUiOutput(root=AgUiCustomEventOutput(event=AgUiCustomEvent(name=name, value=value))))
90
+ except Exception:
91
+ logger.exception("Failed to emit custom event '%s' to the agent stream", name)
@@ -0,0 +1,298 @@
1
+ """Toolkit for progressive chat-history access (outline first, then read by id).
2
+
3
+ Replaces Agno's built-in ``get_chat_history`` (which dumps every message in full)
4
+ with a two-step, token-cheap surface:
5
+
6
+ 1. ``outline_chat_history`` — a metadata-only index (role, who, size, preview) so the
7
+ agent can see *what* exists before loading anything.
8
+ 2. ``read_chat_messages`` — fetch full content only for the message ids that matter.
9
+
10
+ The toolkit is leader-only: it is attached to the head agent / team leader and its
11
+ underlying ``aget_session_messages`` call skips team-member sub-conversations.
12
+
13
+ Note: the tools intentionally take NO ``run_context`` parameter. The session id is
14
+ captured at construction and the runtime Agent/Team is late-bound as ``host`` — so
15
+ every tool parameter is a plain builtin type, which keeps the LLM-facing JSON schema
16
+ correct under ``from __future__ import annotations``.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from itertools import starmap
22
+ from typing import TYPE_CHECKING, Any, ClassVar
23
+
24
+ from digitalkin.community.agno.toolkits.base import DkToolkit
25
+ from digitalkin.logger import logger
26
+
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Callable
29
+
30
+ from agno.media import Audio, File, Image, Video
31
+ from agno.models.message import Message
32
+
33
+ from digitalkin.models.module import ModuleContext
34
+
35
+
36
+ class ChatHistoryTools(DkToolkit):
37
+ """Two-tool chat-history surface bound to a constructed Agent or Team.
38
+
39
+ ``host`` is late-bound after the agent/team is created (the same pattern Agno uses
40
+ for its own history tools, which close over the agent + session). Until bound, the
41
+ tools report that history is unavailable rather than raising.
42
+ """
43
+
44
+ # Agno message roles -> the labels surfaced to the LLM.
45
+ _ROLE_TO_LABEL: ClassVar[dict[str, str]] = {"user": "human", "assistant": "ai", "tool": "tool", "system": "system"}
46
+
47
+ # Requested label -> Agno ``skip_roles`` (which roles to exclude). ``system`` is special-cased.
48
+ _LABEL_TO_SKIP: ClassVar[dict[str, list[str]]] = {
49
+ "human": ["system", "assistant", "tool"],
50
+ "ai": ["system", "user", "tool"],
51
+ "tool": ["system", "user", "assistant"],
52
+ "system": [],
53
+ }
54
+
55
+ def __init__(self, session_id: str | None = None, context: ModuleContext | None = None) -> None:
56
+ """Register the outline + read tools.
57
+
58
+ Args:
59
+ session_id: The session whose history to read. Captured here (it is known at
60
+ agent-construction time) so the tools need no ``run_context`` parameter.
61
+ context: Module context; enables AG-UI notifications via the base toolkit.
62
+ """
63
+ super().__init__(
64
+ name="chat_history_tools",
65
+ tools=[self.outline_chat_history, self.read_chat_messages],
66
+ context=context,
67
+ )
68
+ self._session_id = session_id
69
+ # Late-bound to the runtime Agent (single mode) or Team (team mode).
70
+ self.host: Any = None
71
+
72
+ @staticmethod
73
+ def bind_host(tools: list[Any] | Callable[..., list[Any]] | None, host: Any) -> None:
74
+ """Late-bind the runtime Agent/Team into the ChatHistoryTools instance, if present.
75
+
76
+ The toolkit needs a handle to call ``aget_session_messages``, which only exists once
77
+ the agent/team is constructed. In team mode call this again with the ``Team`` so
78
+ history reads target the team session rather than the bare head agent.
79
+
80
+ Args:
81
+ tools: The head tools — either the raw list or an
82
+ :meth:`AguiTools.make_tools_factory` callable (calling it without a
83
+ RunContext returns the base list). Binds the first ChatHistoryTools
84
+ found; no-op if absent.
85
+ host: The constructed Agent or Team to bind as the history source.
86
+ """
87
+ if callable(tools) and not isinstance(tools, list):
88
+ tools = tools(None)
89
+ if not isinstance(tools, list):
90
+ return
91
+ for tool in tools:
92
+ if isinstance(tool, ChatHistoryTools):
93
+ tool.host = host
94
+ return
95
+
96
+ async def outline_chat_history(
97
+ self,
98
+ role: str | None = None,
99
+ first: int | None = None,
100
+ last: int | None = None,
101
+ offset: int = 0,
102
+ ) -> str:
103
+ """List the conversation as a cheap metadata index — call this FIRST.
104
+
105
+ Returns one lightweight row per message (role, who, timestamp, size and a short
106
+ preview) WITHOUT the full content, so it is safe to scan a long thread. Once you
107
+ know which messages you need, call ``read_chat_messages`` with their ids to get
108
+ full content. Prefer this over loading everything.
109
+
110
+ Args:
111
+ role: Filter by message type: "human", "ai", "tool", or "system".
112
+ Omit to get all messages except the system prompt.
113
+ first: Return only the first N messages (oldest). Use this to reach the start
114
+ of the conversation, e.g. the user's first request.
115
+ last: Return only the last N messages (most recent). Mutually exclusive with first.
116
+ offset: Skip this many messages from the relevant end (for pagination).
117
+
118
+ Returns:
119
+ JSON string: {"total", "returned", "offset", "messages": [{"ord", "id", "role",
120
+ "ts", "chars", "preview", ...}]}. "total" is the full count after filtering, so
121
+ an empty "messages" with "total": 0 means the thread is genuinely empty.
122
+ """
123
+ if role is not None and role not in self._LABEL_TO_SKIP:
124
+ msg = f"invalid role '{role}'; use one of: human, ai, tool, system"
125
+ return self._fail(msg, tool="outline_chat_history")
126
+
127
+ skip_roles = self._LABEL_TO_SKIP[role] if role is not None else ["system"]
128
+ messages = await self._fetch(skip_roles)
129
+ if messages is None:
130
+ return self._fail("chat history is not available", tool="outline_chat_history")
131
+ if role == "system":
132
+ messages = [m for m in messages if m.role == "system"]
133
+
134
+ rows = list(starmap(self._index_row, enumerate(messages)))
135
+ total = len(rows)
136
+
137
+ if first is not None:
138
+ sliced = rows[offset : offset + max(first, 0)]
139
+ elif last is not None:
140
+ end = max(total - offset, 0)
141
+ start = max(end - max(last, 0), 0)
142
+ sliced = rows[start:end]
143
+ else:
144
+ sliced = rows[offset:]
145
+
146
+ return self._ok(
147
+ {"total": total, "returned": len(sliced), "offset": offset, "messages": sliced},
148
+ tool="outline_chat_history",
149
+ )
150
+
151
+ async def read_chat_messages(
152
+ self,
153
+ ids: list[str],
154
+ max_content_chars: int = 4000,
155
+ ) -> str:
156
+ """Fetch the full content of specific messages by id (from ``outline_chat_history``).
157
+
158
+ Use the "id" values returned by ``outline_chat_history`` — they are stable even as
159
+ the conversation grows (unlike the "ord" position). Long bodies are truncated to
160
+ ``max_content_chars``; attached media is returned as a reference, never inlined.
161
+
162
+ Args:
163
+ ids: The message ids to read, taken from an earlier ``outline_chat_history`` call.
164
+ max_content_chars: Truncate each message body to this many characters (default 4000).
165
+
166
+ Returns:
167
+ JSON string: {"messages": [{"id", "role", "ts", "content", ...}], "missing": [...]}.
168
+ Any requested id that no longer exists is listed under "missing".
169
+ """
170
+ if not ids:
171
+ return self._ok({"messages": [], "missing": []}, tool="read_chat_messages")
172
+
173
+ messages = await self._fetch(skip_roles=[])
174
+ if messages is None:
175
+ return self._fail("chat history is not available", tool="read_chat_messages")
176
+
177
+ by_id = {message.id: message for message in messages}
178
+ out: list[dict[str, Any]] = []
179
+ missing: list[str] = []
180
+ for message_id in ids:
181
+ message = by_id.get(message_id)
182
+ if message is None:
183
+ missing.append(message_id)
184
+ else:
185
+ out.append(self._full_row(message, max_content_chars))
186
+
187
+ return self._ok({"messages": out, "missing": missing}, tool="read_chat_messages")
188
+
189
+ async def _fetch(self, skip_roles: list[str]) -> list[Message] | None:
190
+ """Load session messages via the bound agent/team, or None if unavailable.
191
+
192
+ Args:
193
+ skip_roles: Roles to exclude (passed to Agno's ``aget_session_messages``).
194
+
195
+ Returns:
196
+ The deduplicated session messages, or None if no host is bound or the call fails.
197
+ """
198
+ if self.host is None:
199
+ logger.warning("ChatHistoryTools called before host was bound")
200
+ return None
201
+ try:
202
+ return await self.host.aget_session_messages(
203
+ session_id=self._session_id,
204
+ skip_roles=skip_roles,
205
+ skip_history_messages=True,
206
+ )
207
+ except Exception as error:
208
+ logger.warning("ChatHistoryTools: failed to load session messages: %s", error)
209
+ return None
210
+
211
+ def _index_row(self, ordinal: int, message: Message) -> dict[str, Any]:
212
+ """Build a metadata-only index row for one message.
213
+
214
+ Args:
215
+ ordinal: Position of the message in the filtered list (display-only).
216
+ message: The Agno message.
217
+
218
+ Returns:
219
+ A compact dict with role, id, timestamp, size and a short preview.
220
+ """
221
+ content = message.get_content_string() or ""
222
+ row: dict[str, Any] = {
223
+ "ord": ordinal,
224
+ "id": message.id,
225
+ "role": self._ROLE_TO_LABEL.get(message.role, message.role),
226
+ "ts": message.created_at,
227
+ "chars": len(content),
228
+ "preview": content[:120],
229
+ }
230
+ if message.images or message.files or message.videos or message.audio:
231
+ row["has_media"] = True
232
+ if message.from_history:
233
+ row["from_history"] = True
234
+ if message.role == "tool":
235
+ row["name"] = message.tool_name
236
+ if message.tool_call_error:
237
+ row["error"] = True
238
+ return row
239
+
240
+ def _full_row(self, message: Message, max_content_chars: int) -> dict[str, Any]:
241
+ """Build a full-content row for one message, truncating the body if needed.
242
+
243
+ Args:
244
+ message: The Agno message.
245
+ max_content_chars: Maximum body length before truncation.
246
+
247
+ Returns:
248
+ A dict with the (possibly truncated) content plus media references.
249
+ """
250
+ content = message.get_content_string() or ""
251
+ truncated = len(content) > max_content_chars
252
+ if truncated:
253
+ content = content[:max_content_chars] + " […truncated]"
254
+
255
+ row: dict[str, Any] = {
256
+ "id": message.id,
257
+ "role": self._ROLE_TO_LABEL.get(message.role, message.role),
258
+ "ts": message.created_at,
259
+ "content": content,
260
+ }
261
+ if truncated:
262
+ row["truncated"] = True
263
+ if message.role == "tool":
264
+ row["name"] = message.tool_name
265
+ if message.tool_call_error:
266
+ row["error"] = True
267
+ media = self._media_refs(message)
268
+ if media:
269
+ row["media"] = media
270
+ return row
271
+
272
+ @staticmethod
273
+ def _media_refs(message: Message) -> list[dict[str, Any]]:
274
+ """Build reference descriptors for attached media — never the raw bytes.
275
+
276
+ Args:
277
+ message: The Agno message.
278
+
279
+ Returns:
280
+ A list of {"kind", "id", "mime_type", "format"} descriptors.
281
+ """
282
+ groups: tuple[tuple[str, Any], ...] = (
283
+ ("image", message.images),
284
+ ("audio", message.audio),
285
+ ("video", message.videos),
286
+ ("file", message.files),
287
+ )
288
+ refs: list[dict[str, Any]] = []
289
+ for kind, items in groups:
290
+ for item in items or []:
291
+ media_item: Image | Audio | Video | File = item
292
+ refs.append({
293
+ "kind": kind,
294
+ "id": media_item.id,
295
+ "mime_type": media_item.mime_type,
296
+ "format": media_item.format,
297
+ })
298
+ return refs
@@ -0,0 +1,57 @@
1
+ """One-call assembler for the default DigitalKin toolkits."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
8
+ from digitalkin.community.agno.toolkits.registry import RegistryTools
9
+ from digitalkin.community.agno.toolkits.user_profile import UserProfileTools
10
+
11
+ if TYPE_CHECKING:
12
+ from collections.abc import Callable
13
+
14
+ from agno.tools import Toolkit
15
+
16
+ from digitalkin.models.module.module_context import ModuleContext
17
+
18
+
19
+ class DefaultToolkits:
20
+ """Assemble the default DigitalKin toolkits (chat history, user profile, registry).
21
+
22
+ Two-phase usage — ChatHistoryTools needs the constructed Agent/Team::
23
+
24
+ tools = DefaultToolkits.build(context, session_id=sid)
25
+ agent = Agent(tools=AguiTools.make_tools_factory(tools), cache_callables=False, ...)
26
+ DefaultToolkits.bind_host(tools, agent)
27
+
28
+ In team mode call :meth:`bind_host` again with the ``Team`` so history reads
29
+ target the team session rather than the bare head agent.
30
+ """
31
+
32
+ @staticmethod
33
+ def build(context: ModuleContext, session_id: str | None = None) -> list[Toolkit]:
34
+ """Build the default toolkits from a module context.
35
+
36
+ Args:
37
+ context: The module context carrying the user_profile and registry services.
38
+ session_id: The Agno session whose chat history should be readable.
39
+
40
+ Returns:
41
+ [ChatHistoryTools, UserProfileTools, RegistryTools].
42
+ """
43
+ return [
44
+ ChatHistoryTools(session_id=session_id, context=context),
45
+ UserProfileTools(context.user_profile, context=context),
46
+ RegistryTools(context.registry, context=context),
47
+ ]
48
+
49
+ @staticmethod
50
+ def bind_host(tools: list[Any] | Callable[..., list[Any]] | None, host: Any) -> None:
51
+ """Late-bind the constructed Agent/Team into ChatHistoryTools (delegates).
52
+
53
+ Args:
54
+ tools: The tools list (or a make_tools_factory callable) containing the toolkits.
55
+ host: The constructed Agent or Team to bind as the history source.
56
+ """
57
+ ChatHistoryTools.bind_host(tools, host)