digitalkin 1.0.5.dev6__tar.gz → 1.1.0.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 (278) hide show
  1. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/PKG-INFO +1 -1
  2. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/pyproject.toml +1 -1
  3. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/__init__.py +2 -0
  5. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/defaults.py +4 -2
  6. digitalkin-1.1.0.dev0/src/digitalkin/community/agno/toolkits/knowledge.py +113 -0
  7. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/module_server.py +10 -4
  8. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module_context.py +6 -0
  9. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/__init__.py +3 -0
  10. digitalkin-1.1.0.dev0/src/digitalkin/models/services/knowledge.py +61 -0
  11. digitalkin-1.1.0.dev0/src/digitalkin/models/settings/knowledge.py +35 -0
  12. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +1 -0
  13. digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/__init__.py +16 -0
  14. digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/default_knowledge.py +88 -0
  15. digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/exceptions.py +5 -0
  16. digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/grpc_knowledge.py +145 -0
  17. digitalkin-1.1.0.dev0/src/digitalkin/services/knowledge/knowledge_strategy.py +114 -0
  18. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/services_config.py +11 -2
  19. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/services_models.py +2 -0
  20. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/PKG-INFO +1 -1
  21. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/SOURCES.txt +8 -0
  22. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/LICENSE +0 -0
  23. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/README.md +0 -0
  24. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/__init__.py +0 -0
  25. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/__init__.py +0 -0
  26. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/mock_pb2.py +0 -0
  27. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  28. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_async_insecure.py +0 -0
  29. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_async_secure.py +0 -0
  30. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_sync_insecure.py +0 -0
  31. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/base_server/server_sync_secure.py +0 -0
  32. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/__init__.py +0 -0
  33. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/echo_module.py +0 -0
  34. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/__init__.py +0 -0
  35. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/input.py +0 -0
  36. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/output.py +0 -0
  37. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/secret.py +0 -0
  38. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/models/setup.py +0 -0
  39. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/server.py +0 -0
  40. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/triggers/__init__.py +0 -0
  41. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/bench_module/triggers/message_trigger.py +0 -0
  42. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/__init__.py +0 -0
  43. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/archetype_with_tools_module.py +0 -0
  44. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/cpu_intensive_module.py +0 -0
  45. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/dynamic_setup_module.py +0 -0
  46. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/minimal_llm_module.py +0 -0
  47. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/modules/text_transform_module.py +0 -0
  48. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  49. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  50. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  51. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  52. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  53. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/monitoring/tests/test_metrics.py +0 -0
  54. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/client.py +0 -0
  55. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/echo_module.py +0 -0
  56. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/__init__.py +0 -0
  57. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/input.py +0 -0
  58. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/output.py +0 -0
  59. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/secret.py +0 -0
  60. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/models/setup.py +0 -0
  61. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/server.py +0 -0
  62. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/triggers/__init__.py +0 -0
  63. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/redis_demo/triggers/message_trigger.py +0 -0
  64. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/services/filesystem_module.py +0 -0
  65. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/examples/services/storage_module.py +0 -0
  66. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/setup.cfg +0 -0
  67. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/__init__.py +0 -0
  68. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/__init__.py +0 -0
  69. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/__init__.py +0 -0
  70. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/agno_adapter.py +0 -0
  71. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/agui_tools.py +0 -0
  72. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/hitl.py +0 -0
  73. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/models.py +0 -0
  74. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/module_toolkit.py +0 -0
  75. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/base.py +0 -0
  76. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/chat_history.py +0 -0
  77. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/__init__.py +0 -0
  78. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/action.py +0 -0
  79. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/base.py +0 -0
  80. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/__init__.py +0 -0
  81. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/action.py +0 -0
  82. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/kins/kit.py +0 -0
  83. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/__init__.py +0 -0
  84. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/action.py +0 -0
  85. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/loader/kit.py +0 -0
  86. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/__init__.py +0 -0
  87. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/action.py +0 -0
  88. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/services/kit.py +0 -0
  89. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/__init__.py +0 -0
  90. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/action.py +0 -0
  91. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/registry/tools/kit.py +0 -0
  92. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/community/agno/toolkits/user_profile.py +0 -0
  93. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/__init__.py +0 -0
  94. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/common/__init__.py +0 -0
  95. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/common/factories.py +0 -0
  96. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/exceptions.py +0 -0
  97. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/__init__.py +0 -0
  98. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  99. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  100. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/__init__.py +0 -0
  101. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/step_timer.py +0 -0
  102. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/profiling/task_profiler.py +0 -0
  103. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/__init__.py +0 -0
  104. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/bulkhead.py +0 -0
  105. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/resilience/task_supervisor.py +0 -0
  106. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/__init__.py +0 -0
  107. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  108. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  109. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/module_runner.py +0 -0
  110. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/__init__.py +0 -0
  111. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/proto_streams.py +0 -0
  112. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_client.py +0 -0
  113. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_idempotency.py +0 -0
  114. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/redis/redis_signal.py +0 -0
  115. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  116. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  117. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/core/task_manager/task_session.py +0 -0
  118. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/exceptions.py +0 -0
  119. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/__init__.py +0 -0
  120. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  121. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/exceptions.py +0 -0
  122. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/gateway_servicer.py +0 -0
  123. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/__init__.py +0 -0
  124. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/permission.py +0 -0
  125. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/request_ids.py +0 -0
  126. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/interceptors/validation.py +0 -0
  127. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/m2m_call_registry.py +0 -0
  128. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
  129. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/stream_registry.py +0 -0
  130. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/stream_session.py +0 -0
  131. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  132. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/circuit_breaker.py +0 -0
  133. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  134. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  135. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  136. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/grpc_servers/utils/validators.py +0 -0
  137. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/logger.py +0 -0
  138. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/__init__.py +0 -0
  139. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/agui_mixin.py +0 -0
  140. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/base_mixin.py +0 -0
  141. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/cost_mixin.py +0 -0
  142. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  143. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  144. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/logger_mixin.py +0 -0
  145. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/mixins/storage_mixin.py +0 -0
  146. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/__init__.py +0 -0
  147. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/__init__.py +0 -0
  148. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/job_manager_models.py +0 -0
  149. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/redis.py +0 -0
  150. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/core/task_monitor.py +0 -0
  151. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/events/__init__.py +0 -0
  152. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/events/agent_events.py +0 -0
  153. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  154. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/circuit_breaker.py +0 -0
  155. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/m2m.py +0 -0
  156. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/models.py +0 -0
  157. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/stream_error_codes.py +0 -0
  158. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/grpc_servers/types.py +0 -0
  159. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/__init__.py +0 -0
  160. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/ag_ui.py +0 -0
  161. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/base_types.py +0 -0
  162. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/knowledge_files.py +0 -0
  163. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/loaded_tools.py +0 -0
  164. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module.py +0 -0
  165. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/module_types.py +0 -0
  166. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/request_metadata.py +0 -0
  167. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/select_schema.py +0 -0
  168. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/setup_types.py +0 -0
  169. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/tool_cache.py +0 -0
  170. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/tool_reference.py +0 -0
  171. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/module/utility.py +0 -0
  172. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/cost.py +0 -0
  173. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/filesystem.py +0 -0
  174. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/registry.py +0 -0
  175. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/services.py +0 -0
  176. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/services/storage.py +0 -0
  177. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/__init__.py +0 -0
  178. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/certificate.py +0 -0
  179. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/__init__.py +0 -0
  180. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/channel.py +0 -0
  181. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/circuit_breaker.py +0 -0
  182. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/client.py +0 -0
  183. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/client/grpc.py +0 -0
  184. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/gateway.py +0 -0
  185. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/log.py +0 -0
  186. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/module.py +0 -0
  187. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/profiling.py +0 -0
  188. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/queue.py +0 -0
  189. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/redis.py +0 -0
  190. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/registry.py +0 -0
  191. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/resilience.py +0 -0
  192. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/__init__.py +0 -0
  193. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/channel.py +0 -0
  194. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/grpc.py +0 -0
  195. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/server.py +0 -0
  196. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/server/servicer.py +0 -0
  197. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/task_manager.py +0 -0
  198. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/utils/__init__.py +0 -0
  199. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/settings/utils/channel.py +0 -0
  200. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/utils/__init__.py +0 -0
  201. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/models/utils/dynamic_schema.py +0 -0
  202. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/__init__.py +0 -0
  203. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/_base_module.py +0 -0
  204. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/archetype_module.py +0 -0
  205. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/tool_module.py +0 -0
  206. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/trigger_handler.py +0 -0
  207. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/__init__.py +0 -0
  208. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  209. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  210. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/py.typed +0 -0
  211. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/__init__.py +0 -0
  212. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/base_strategy.py +0 -0
  213. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/__init__.py +0 -0
  214. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  215. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/default_communication.py +0 -0
  216. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/exceptions.py +0 -0
  217. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  218. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/__init__.py +0 -0
  219. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  220. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/default_cost.py +0 -0
  221. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/exceptions.py +0 -0
  222. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  223. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/__init__.py +0 -0
  224. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  225. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/exceptions.py +0 -0
  226. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  227. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  228. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/__init__.py +0 -0
  229. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/default_identity.py +0 -0
  230. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  231. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/__init__.py +0 -0
  232. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/default_registry.py +0 -0
  233. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/exceptions.py +0 -0
  234. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/grpc_registry.py +0 -0
  235. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/registry/registry_strategy.py +0 -0
  236. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/__init__.py +0 -0
  237. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/default_secret.py +0 -0
  238. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/exceptions.py +0 -0
  239. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/grpc_secret.py +0 -0
  240. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/secret/secret_strategy.py +0 -0
  241. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/__init__.py +0 -0
  242. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/default_setup.py +0 -0
  243. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/exceptions.py +0 -0
  244. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  245. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  246. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/__init__.py +0 -0
  247. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/default_storage.py +0 -0
  248. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/exceptions.py +0 -0
  249. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  250. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  251. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/__init__.py +0 -0
  252. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/default_task_manager.py +0 -0
  253. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/exceptions.py +0 -0
  254. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/redis_task_manager.py +0 -0
  255. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/task_manager/task_manager_strategy.py +0 -0
  256. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/__init__.py +0 -0
  257. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  258. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/exceptions.py +0 -0
  259. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  260. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  261. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/__init__.py +0 -0
  262. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/arg_parser.py +0 -0
  263. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/conditional_schema.py +0 -0
  264. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/development_mode_action.py +0 -0
  265. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/dynamic_schema.py +0 -0
  266. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/env_manager.py +0 -0
  267. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/env_template.py +0 -0
  268. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/exceptions.py +0 -0
  269. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/json_structure.py +0 -0
  270. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  271. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/package_discover.py +0 -0
  272. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/proto_utils.py +0 -0
  273. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/schema_splitter.py +0 -0
  274. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin/utils/setup_content_validator.py +0 -0
  275. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  276. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/requires.txt +0 -0
  277. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.dev0}/src/digitalkin.egg-info/top_level.txt +0 -0
  278. {digitalkin-1.0.5.dev6 → digitalkin-1.1.0.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.5.dev6
3
+ Version: 1.1.0.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
@@ -43,7 +43,7 @@
43
43
  "pydantic>=2.12.4",
44
44
  "redis[hiredis]>=7.4.0,<9",
45
45
  ]
46
- version = "1.0.5.dev6"
46
+ version = "1.1.0.dev0"
47
47
 
48
48
  [project.optional-dependencies]
49
49
  agno = [ "agno>=3.1.1,<4" ]
@@ -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.dev6"
8
+ __version__ = "1.1.0.dev0"
@@ -8,6 +8,7 @@ Requires the optional ``agno`` dependency — importing this subpackage without
8
8
  from digitalkin.community.agno.toolkits.base import DkToolkit
9
9
  from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
10
10
  from digitalkin.community.agno.toolkits.defaults import DefaultToolkits
11
+ from digitalkin.community.agno.toolkits.knowledge import KnowledgeTools
11
12
  from digitalkin.community.agno.toolkits.registry.kins.kit import KinsManager
12
13
  from digitalkin.community.agno.toolkits.registry.loader.kit import LoadManager
13
14
  from digitalkin.community.agno.toolkits.registry.services.kit import ServicesManager
@@ -19,6 +20,7 @@ __all__ = [
19
20
  "DefaultToolkits",
20
21
  "DkToolkit",
21
22
  "KinsManager",
23
+ "KnowledgeTools",
22
24
  "LoadManager",
23
25
  "ServicesManager",
24
26
  "ToolsManager",
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from digitalkin.community.agno.toolkits.chat_history import ChatHistoryTools
8
+ from digitalkin.community.agno.toolkits.knowledge import KnowledgeTools
8
9
  from digitalkin.community.agno.toolkits.registry.kins.kit import KinsManager
9
10
  from digitalkin.community.agno.toolkits.registry.loader.kit import LoadManager
10
11
  from digitalkin.community.agno.toolkits.registry.services.kit import ServicesManager
@@ -20,7 +21,7 @@ if TYPE_CHECKING:
20
21
 
21
22
 
22
23
  class DefaultToolkits:
23
- """Assemble the default DigitalKin toolkits (chat history, user profile, registry).
24
+ """Assemble the default DigitalKin toolkits (chat history, user profile, knowledge, registry).
24
25
 
25
26
  Two-phase usage — ChatHistoryTools needs the constructed Agent/Team::
26
27
 
@@ -46,12 +47,13 @@ class DefaultToolkits:
46
47
  session_id: The Agno session whose chat history should be readable.
47
48
 
48
49
  Returns:
49
- [ChatHistoryTools, UserProfileTools,
50
+ [ChatHistoryTools, UserProfileTools, KnowledgeTools,
50
51
  (ToolsManager, ServicesManager, KinsManager)?, LoadManager].
51
52
  """
52
53
  tools: list[Toolkit] = [
53
54
  ChatHistoryTools(session_id=session_id, context=context),
54
55
  UserProfileTools(context.user_profile, context=context),
56
+ KnowledgeTools(context.knowledge, context=context),
55
57
  ]
56
58
  if context.setup is not None:
57
59
  tools.extend((
@@ -0,0 +1,113 @@
1
+ """Toolkit exposing the user's connected knowledge base to the agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from digitalkin.community.agno.toolkits.base import DkToolkit
8
+ from digitalkin.logger import logger
9
+ from digitalkin.models.services.knowledge import Citation, Modality
10
+ from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
11
+
12
+ if TYPE_CHECKING:
13
+ from digitalkin.models.module import ModuleContext
14
+ from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
15
+
16
+
17
+ class KnowledgeTools(DkToolkit):
18
+ """Toolkit that lets the agent search the enterprise knowledge base.
19
+
20
+ What the search reaches is what the *current user* connected and may read: the
21
+ permission filter is compiled into the query by the platform, so there is no identity
22
+ to pass and no result to filter afterwards.
23
+
24
+ An empty answer is a legitimate answer — nothing matched, or nothing is connected —
25
+ and is reported as a success with zero results so the agent says so rather than retrying.
26
+ """
27
+
28
+ def __init__(self, knowledge: KnowledgeStrategy, context: ModuleContext | None = None) -> None:
29
+ """Initialize the toolkit with the ``search_knowledge_base`` tool.
30
+
31
+ Args:
32
+ knowledge: The module's knowledge service strategy.
33
+ context: Module context; enables AG-UI notifications via the base toolkit.
34
+ """
35
+ self._knowledge = knowledge
36
+ super().__init__(
37
+ name="knowledge_tools",
38
+ tools=[self.search_knowledge_base],
39
+ context=context,
40
+ )
41
+
42
+ @staticmethod
43
+ def _row(citation: Citation) -> dict[str, Any]:
44
+ """Trim a citation to what an agent can reason and cite from.
45
+
46
+ ``score`` is dropped on purpose: it is a fused rank comparable only within one
47
+ answer, and a model shown a number reads it as a confidence.
48
+
49
+ Args:
50
+ citation: The citation to render.
51
+
52
+ Returns:
53
+ The fields worth spending context on.
54
+ """
55
+ row: dict[str, Any] = {
56
+ "document_id": citation.document_id,
57
+ "title": citation.title,
58
+ "passage": citation.snippet,
59
+ "source": citation.source,
60
+ "source_url": citation.source_url,
61
+ }
62
+ if headings := citation.heading_path:
63
+ row["section"] = " > ".join(headings)
64
+ if citation.modality not in {Modality.TEXT, Modality.UNSPECIFIED}:
65
+ row["modality"] = citation.modality.value
66
+ return row
67
+
68
+ async def search_knowledge_base(
69
+ self,
70
+ query: str,
71
+ sources: list[str] | None = None,
72
+ limit: int = 10,
73
+ ) -> str:
74
+ """Search the user's own documents — their connected Google Drive, Notion, and the like.
75
+
76
+ Use this whenever the answer could live in the user's company documents rather than
77
+ in your general knowledge: internal decisions, meeting notes, specifications,
78
+ contracts, processes, numbers. Prefer one precise question in natural language over
79
+ keywords; the search is semantic as well as lexical.
80
+
81
+ Each result is a whole passage, not an excerpt, plus the URL of the document it came
82
+ from — quote the passage and cite the ``source_url`` rather than paraphrasing blindly.
83
+ Only documents this user is allowed to read are ever returned, so anything you get
84
+ back is safe to show them.
85
+
86
+ An empty result list means nothing matched or nothing is connected: say so, and do
87
+ not call the tool again with the same question.
88
+
89
+ Args:
90
+ query: The question to answer, in natural language (1-4000 characters).
91
+ sources: Restrict the search to these connectors, e.g. ``["google_drive"]`` or
92
+ ``["notion"]``. Lowercase connector names only, never a display name like
93
+ ``"Google Drive"``. Omit it to search everything the user connected, which
94
+ is almost always what you want.
95
+ limit: How many documents to return, 1-50 (default 10). Several passages of one
96
+ document collapse into a single result, so this counts documents.
97
+
98
+ Returns:
99
+ JSON string: ``{"output": {"results": [{"document_id", "title", "passage",
100
+ "source", "source_url", "section"?}], "returned": N}}``, or ``{"error": ...}``
101
+ when the knowledge base could not be reached.
102
+ """
103
+ try:
104
+ citations = await self._knowledge.search(query, sources=sources, limit=limit)
105
+ except ValueError as error:
106
+ return self._fail(str(error), tool="search_knowledge_base")
107
+ except KnowledgeServiceError as error:
108
+ logger.warning("KnowledgeTools: search failed: %s", error)
109
+ return self._fail("the knowledge base could not be reached", tool="search_knowledge_base")
110
+
111
+ rows = [self._row(citation) for citation in citations]
112
+ await self._notify("knowledge_searched", {"query": query, "sources": sources or [], "results": len(rows)})
113
+ return self._ok({"results": rows, "returned": len(rows)}, tool="search_knowledge_base")
@@ -65,7 +65,7 @@ class ModuleServer(BaseServer):
65
65
  self._gateway_servicer: GatewayServicer | None = None
66
66
  self._gateway_redis_client: RedisClient | None = None
67
67
 
68
- self._prepare_registry_config()
68
+ self._prepare_platform_configs()
69
69
 
70
70
  def _register_servicers(self) -> None:
71
71
  """Register module and gateway servicers.
@@ -207,14 +207,20 @@ class ModuleServer(BaseServer):
207
207
  await GrpcClientWrapper.close_all_cached_channels()
208
208
  Bulkhead.clear_all()
209
209
 
210
- def _prepare_registry_config(self) -> None:
211
- """Inject registry client config into module_class for spawned instances."""
210
+ def _prepare_platform_configs(self) -> None:
211
+ """Inject the Service Provider client config into module_class for spawned instances.
212
+
213
+ Covers the services a module never configures itself because they are platform
214
+ machinery served by that same provider: the registry, and the knowledge base the
215
+ customer connected. The server's address wins, as it did for the registry alone.
216
+ """
212
217
  if not self.client_config:
213
218
  return
214
219
 
215
220
  if "services_config_params" not in self.module_class.__dict__:
216
221
  self.module_class.services_config_params = dict(self.module_class.services_config_params)
217
- self.module_class.services_config_params["registry"] = {"client_config": self.client_config}
222
+ for service in ("registry", "knowledge"):
223
+ self.module_class.services_config_params[service] = {"client_config": self.client_config}
218
224
 
219
225
  async def _init_and_register(self) -> None:
220
226
  """Initialize registry client, health-check, and register.
@@ -20,6 +20,7 @@ from digitalkin.services.communication.exceptions import ToolCallError
20
20
  from digitalkin.services.cost.cost_strategy import CostStrategy
21
21
  from digitalkin.services.filesystem.filesystem_strategy import FilesystemStrategy
22
22
  from digitalkin.services.identity.identity_strategy import IdentityStrategy
23
+ from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
23
24
  from digitalkin.services.registry.exceptions import RegistryModuleNotFoundError
24
25
  from digitalkin.services.registry.registry_strategy import RegistryStrategy
25
26
  from digitalkin.services.secret.secret_strategy import SecretStrategy
@@ -104,6 +105,7 @@ class ModuleContext:
104
105
  cost: CostStrategy
105
106
  filesystem: FilesystemStrategy
106
107
  identity: IdentityStrategy
108
+ knowledge: KnowledgeStrategy
107
109
  registry: RegistryStrategy
108
110
  secret: SecretStrategy
109
111
  setup: SetupStrategy | None
@@ -127,6 +129,7 @@ class ModuleContext:
127
129
  cost: CostStrategy,
128
130
  filesystem: FilesystemStrategy,
129
131
  identity: IdentityStrategy,
132
+ knowledge: KnowledgeStrategy,
130
133
  registry: RegistryStrategy,
131
134
  secret: SecretStrategy,
132
135
  storage: StorageStrategy,
@@ -149,6 +152,7 @@ class ModuleContext:
149
152
  cost: CostStrategy.
150
153
  filesystem: FilesystemStrategy.
151
154
  identity: IdentityStrategy.
155
+ knowledge: KnowledgeStrategy.
152
156
  registry: RegistryStrategy.
153
157
  secret: SecretStrategy.
154
158
  storage: StorageStrategy.
@@ -169,6 +173,7 @@ class ModuleContext:
169
173
  self.cost = cost
170
174
  self.filesystem = filesystem
171
175
  self.identity = identity
176
+ self.knowledge = knowledge
172
177
  self.registry = registry
173
178
  self.secret = secret
174
179
  self.setup = setup
@@ -574,6 +579,7 @@ class ModuleContext:
574
579
  ("cost", self.cost),
575
580
  ("storage", self.storage),
576
581
  ("registry", self.registry),
582
+ ("knowledge", self.knowledge),
577
583
  ("filesystem", self.filesystem),
578
584
  ("user_profile", self.user_profile),
579
585
  ("secret", self.secret),
@@ -1,14 +1,17 @@
1
1
  """This module contains the models for the services."""
2
2
 
3
3
  from digitalkin.models.services.filesystem import FileMetadata, FileType, FileUploadMetadata
4
+ from digitalkin.models.services.knowledge import Citation, Modality
4
5
  from digitalkin.models.services.storage import BaseMessage, BaseRole, ChatHistory, Role
5
6
 
6
7
  __all__ = [
7
8
  "BaseMessage",
8
9
  "BaseRole",
9
10
  "ChatHistory",
11
+ "Citation",
10
12
  "FileMetadata",
11
13
  "FileType",
12
14
  "FileUploadMetadata",
15
+ "Modality",
13
16
  "Role",
14
17
  ]
@@ -0,0 +1,61 @@
1
+ """Knowledge-service data models.
2
+
3
+ The knowledge service searches the enterprise knowledge base a user has connected
4
+ (Google Drive, Notion, ...) through the Context Platform. It answers with citations:
5
+ one per document, carrying the passage that matched and the URL to the original.
6
+ """
7
+
8
+ from enum import Enum
9
+ from typing import Any
10
+
11
+ from pydantic import BaseModel, Field
12
+
13
+
14
+ class Modality(str, Enum):
15
+ """What kind of content a citation's passage is.
16
+
17
+ Member names mirror the proto ``Modality`` enum, whose values are bare since
18
+ protocol 1.2.0 (``TEXT``, ``IMAGE``, ...) except ``MODALITY_UNSPECIFIED``: they are
19
+ looked up by name from the wire value, so they must match.
20
+ """
21
+
22
+ UNSPECIFIED = "unspecified"
23
+ TEXT = "text"
24
+ IMAGE = "image"
25
+ PAGE = "page"
26
+ SLIDE = "slide"
27
+ TABLE = "table"
28
+ AUDIO = "audio"
29
+ VIDEO = "video"
30
+
31
+
32
+ class Citation(BaseModel):
33
+ """One document the search matched, with the passage that matched it.
34
+
35
+ A document contributes a single citation however many of its passages matched,
36
+ which is why ``limit`` counts documents and not passages.
37
+ """
38
+
39
+ document_id: str = ""
40
+ title: str = ""
41
+ snippet: str = ""
42
+ score: float = 0.0
43
+ """Fused rank, NOT a similarity: comparable only against the other citations of the
44
+ same answer, and never to be shown as a confidence."""
45
+ source: str = ""
46
+ """The connector the document came from, e.g. ``google_drive`` or ``notion``."""
47
+ source_url: str = ""
48
+ modality: Modality = Modality.UNSPECIFIED
49
+ locator: dict[str, Any] = Field(default_factory=dict)
50
+ """Where the passage sits in the document: ``index``, ``start``, ``end``, ``heading_path``."""
51
+ metadata: dict[str, Any] = Field(default_factory=dict)
52
+
53
+ @property
54
+ def heading_path(self) -> list[str]:
55
+ """The document headings leading to the passage, outermost first.
56
+
57
+ Returns:
58
+ The heading path, or an empty list when the locator carries none.
59
+ """
60
+ path = self.locator.get("heading_path")
61
+ return [str(item) for item in path] if isinstance(path, list) else []
@@ -0,0 +1,35 @@
1
+ """Knowledge-scope runtime settings."""
2
+
3
+ from functools import lru_cache
4
+
5
+ from pydantic import Field
6
+ from pydantic_settings import BaseSettings, SettingsConfigDict
7
+
8
+
9
+ class KnowledgeSettings(BaseSettings):
10
+ """Knowledge client runtime configuration."""
11
+
12
+ model_config = SettingsConfigDict(env_prefix="DIGITALKIN_KNOWLEDGE_", case_sensitive=False)
13
+
14
+ search_timeout_s: float = Field(
15
+ default=10.0,
16
+ gt=0,
17
+ description="Per-call deadline for a knowledge search (shorter than the global gRPC default).",
18
+ )
19
+ default_limit: int = Field(
20
+ default=10,
21
+ ge=1,
22
+ description="Documents returned when a caller asks for no particular number.",
23
+ )
24
+
25
+
26
+ @lru_cache(maxsize=1)
27
+ def get_knowledge_settings() -> KnowledgeSettings:
28
+ """Process-wide ``KnowledgeSettings`` singleton.
29
+
30
+ Tests must call ``get_knowledge_settings.cache_clear()`` after mutating env.
31
+
32
+ Returns:
33
+ The shared ``KnowledgeSettings`` instance.
34
+ """
35
+ return KnowledgeSettings()
@@ -44,6 +44,7 @@ class HealthcheckServicesTrigger(TriggerHandler, BaseMixin):
44
44
  "cost": context.cost,
45
45
  "filesystem": context.filesystem,
46
46
  "registry": context.registry,
47
+ "knowledge": context.knowledge,
47
48
  "user_profile": context.user_profile,
48
49
  }
49
50
  services_status: list[ServiceHealthStatus] = []
@@ -0,0 +1,16 @@
1
+ """This module is responsible for handling the knowledge service."""
2
+
3
+ from digitalkin.models.services.knowledge import Citation, Modality
4
+ from digitalkin.services.knowledge.default_knowledge import DefaultKnowledge
5
+ from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
6
+ from digitalkin.services.knowledge.grpc_knowledge import GrpcKnowledge
7
+ from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
8
+
9
+ __all__ = [
10
+ "Citation",
11
+ "DefaultKnowledge",
12
+ "GrpcKnowledge",
13
+ "KnowledgeServiceError",
14
+ "KnowledgeStrategy",
15
+ "Modality",
16
+ ]
@@ -0,0 +1,88 @@
1
+ """Default knowledge implementation."""
2
+
3
+ import re
4
+ from typing import Any
5
+
6
+ from digitalkin.models.services.knowledge import Citation
7
+ from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
8
+
9
+ _WORDS = re.compile(r"\w+", re.UNICODE)
10
+
11
+
12
+ class DefaultKnowledge(KnowledgeStrategy):
13
+ """Local knowledge strategy backed by an in-memory corpus.
14
+
15
+ Keeps ``mode=LOCAL`` usable without the Context Platform: a sandbox or a test seeds
16
+ documents through the strategy config and gets deterministic answers offline::
17
+
18
+ services_config_params = {
19
+ "knowledge": {
20
+ "config": {
21
+ "documents": [
22
+ {
23
+ "document_id": "doc_1",
24
+ "title": "Pricing",
25
+ "snippet": "Apollo moved to per-seat.",
26
+ "source": "google_drive",
27
+ "source_url": "https://...",
28
+ },
29
+ ]
30
+ }
31
+ }
32
+ }
33
+
34
+ Matching is word overlap over title and snippet — enough to exercise a caller, never
35
+ a substitute for the real hybrid search.
36
+ """
37
+
38
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
39
+ """Initialize with the corpus declared in the strategy config."""
40
+ super().__init__(*args, **kwargs)
41
+ documents = (self.config or {}).get("documents") or []
42
+ self._documents: list[Citation] = [
43
+ document if isinstance(document, Citation) else Citation.model_validate(document) for document in documents
44
+ ]
45
+
46
+ @staticmethod
47
+ def _overlap(query: str, document: Citation) -> float:
48
+ """Score a document by how much of the query its text carries.
49
+
50
+ Args:
51
+ query: The search query.
52
+ document: The candidate document.
53
+
54
+ Returns:
55
+ The share of distinct query words found, between 0 and 1.
56
+ """
57
+ wanted = {word.casefold() for word in _WORDS.findall(query)}
58
+ if not wanted:
59
+ return 0.0
60
+ haystack = {word.casefold() for word in _WORDS.findall(f"{document.title} {document.snippet}")}
61
+ return len(wanted & haystack) / len(wanted)
62
+
63
+ async def search(
64
+ self,
65
+ query: str,
66
+ sources: list[str] | None = None,
67
+ limit: int | None = None,
68
+ ) -> list[Citation]:
69
+ """Search the in-memory corpus.
70
+
71
+ Args:
72
+ query: What to look for.
73
+ sources: Restrict to these connectors; ``None`` searches the whole corpus.
74
+ limit: Maximum number of documents to return.
75
+
76
+ Returns:
77
+ The matching documents, best first.
78
+ """
79
+ text, wanted_sources, bounded = self.normalize(query, sources, limit)
80
+ scored = [
81
+ (score, document)
82
+ for document in self._documents
83
+ if (not wanted_sources or document.source in wanted_sources)
84
+ and (score := self._overlap(text, document)) > 0
85
+ ]
86
+ # Title breaks ties, so a corpus always answers in the same order.
87
+ scored.sort(key=lambda pair: (-pair[0], pair[1].title))
88
+ return [document.model_copy(update={"score": score}) for score, document in scored[:bounded]]
@@ -0,0 +1,5 @@
1
+ """Knowledge-specific exceptions."""
2
+
3
+
4
+ class KnowledgeServiceError(Exception):
5
+ """Raised when a knowledge search could not be answered."""
@@ -0,0 +1,145 @@
1
+ """gRPC knowledge client implementation.
2
+
3
+ Searches the enterprise knowledge base through the Service Provider's ContextService,
4
+ which relays to the Context Platform.
5
+
6
+ ``SearchDocumentsRequest`` carries no identity: *who* is searching travels as the ambient
7
+ ``x-mission-id`` metadata every outbound call already gets
8
+ (:class:`~digitalkin.grpc_servers.interceptors.request_ids.RequestIdClientInterceptor`),
9
+ and the Service Provider resolves it into the user and organization the search runs for.
10
+ A module therefore cannot widen its own scope, and cannot forget to narrow it.
11
+ """
12
+
13
+ from typing import Any
14
+
15
+ import grpc
16
+ from agentic_mesh_protocol.context.v1 import (
17
+ context_dto_pb2,
18
+ context_enums_pb2,
19
+ context_messages_pb2,
20
+ context_service_pb2_grpc,
21
+ )
22
+ from google.protobuf import json_format
23
+ from grpc_health.v1 import health_pb2, health_pb2_grpc
24
+
25
+ from digitalkin.grpc_servers.exceptions import PermissionDeniedError, ServerError
26
+ from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
27
+ from digitalkin.grpc_servers.utils.grpc_error_handler import GrpcErrorHandlerMixin
28
+ from digitalkin.logger import logger
29
+ from digitalkin.models.grpc_servers.models import ClientConfig
30
+ from digitalkin.models.services.knowledge import Citation, Modality
31
+ from digitalkin.models.settings.knowledge import get_knowledge_settings
32
+ from digitalkin.services.knowledge.exceptions import KnowledgeServiceError
33
+ from digitalkin.services.knowledge.knowledge_strategy import KnowledgeStrategy
34
+
35
+
36
+ class GrpcKnowledge(KnowledgeStrategy, GrpcClientWrapper, GrpcErrorHandlerMixin):
37
+ """gRPC-based knowledge client talking to the Service Provider's ContextService."""
38
+
39
+ service_name: str = "ContextService"
40
+
41
+ def __init__(
42
+ self,
43
+ mission_id: str,
44
+ setup_id: str,
45
+ setup_version_id: str,
46
+ client_config: ClientConfig,
47
+ config: dict[str, Any] | None = None,
48
+ ) -> None:
49
+ """Initialize the gRPC knowledge client."""
50
+ KnowledgeStrategy.__init__(self, mission_id, setup_id, setup_version_id, config)
51
+ self.service_name = "ContextService"
52
+ self._init_channel(client_config)
53
+ self.stub = self._get_or_create_stub(context_service_pb2_grpc.ContextServiceStub)
54
+ logger.debug("Channel client 'Knowledge' initialized successfully")
55
+
56
+ async def close(self) -> None:
57
+ """Release this instance's pooled gRPC channel ref."""
58
+ await self.close_channel()
59
+
60
+ async def wait_for_ready(self, timeout: float = 1.0) -> bool:
61
+ """Probe the backend via the standard gRPC Health Check service.
62
+
63
+ Args:
64
+ timeout: Max seconds for the round-trip.
65
+
66
+ Returns:
67
+ True if the server responded SERVING, False otherwise.
68
+ """
69
+ health_stub = health_pb2_grpc.HealthStub(self._channel)
70
+ try:
71
+ response = await health_stub.Check( # type: ignore[attr-defined] # grpc_health generated stub lacks typed Check
72
+ health_pb2.HealthCheckRequest(service=""),
73
+ timeout=timeout,
74
+ )
75
+ except grpc.aio.AioRpcError:
76
+ return False
77
+ return response.status == health_pb2.HealthCheckResponse.SERVING
78
+
79
+ @staticmethod
80
+ def _proto_to_citation(citation: context_messages_pb2.Citation) -> Citation:
81
+ """Convert a proto ``Citation`` to the SDK model.
82
+
83
+ Args:
84
+ citation: Proto Citation message.
85
+
86
+ Returns:
87
+ Citation with mapped fields.
88
+ """
89
+ # Only ``MODALITY_UNSPECIFIED`` still carries the prefix; the rest are bare since protocol 1.2.0.
90
+ modality_name = context_enums_pb2.Modality.Name(citation.modality).removeprefix("MODALITY_")
91
+ return Citation(
92
+ document_id=citation.document_id,
93
+ title=citation.title,
94
+ snippet=citation.snippet,
95
+ score=citation.score,
96
+ source=citation.source,
97
+ source_url=citation.source_url,
98
+ modality=Modality[modality_name],
99
+ locator=json_format.MessageToDict(citation.locator),
100
+ metadata=json_format.MessageToDict(citation.metadata),
101
+ )
102
+
103
+ async def search(
104
+ self,
105
+ query: str,
106
+ sources: list[str] | None = None,
107
+ limit: int | None = None,
108
+ ) -> list[Citation]:
109
+ """Search the knowledge base the current user may read.
110
+
111
+ Args:
112
+ query: What to look for, in natural language.
113
+ sources: Restrict the search to these connectors; ``None`` searches every source.
114
+ limit: Maximum number of documents to return; ``None`` uses the configured default.
115
+
116
+ Returns:
117
+ One citation per matching document, best first.
118
+
119
+ Raises:
120
+ ValueError: If the query holds nothing to search for, or a source is not a
121
+ connector name.
122
+ PermissionDeniedError: If the caller is not permitted.
123
+ KnowledgeServiceError: If the gRPC call fails.
124
+ """
125
+ # Normalized before the error-handler scope: an empty query and an unusable source name
126
+ # are permanent conditions, and must reach the caller as a ValueError rather than be
127
+ # wrapped as a retryable service error.
128
+ text, wanted_sources, bounded = self.normalize(query, sources, limit)
129
+
130
+ async with self.handle_grpc_errors("SearchDocuments", KnowledgeServiceError):
131
+ try:
132
+ response = await self.exec_grpc_query(
133
+ "SearchDocuments",
134
+ context_dto_pb2.SearchDocumentsRequest(query=text, sources=wanted_sources, limit=bounded),
135
+ timeout=get_knowledge_settings().search_timeout_s,
136
+ )
137
+ except PermissionDeniedError:
138
+ raise
139
+ except ServerError as e:
140
+ msg = f"Failed to search the knowledge base: {e}"
141
+ logger.error(msg)
142
+ raise KnowledgeServiceError(msg) from e
143
+
144
+ logger.debug("Knowledge search returned %d document(s)", len(response.results))
145
+ return [self._proto_to_citation(citation) for citation in response.results]