digitalkin 0.3.2.dev16__tar.gz → 0.3.2.dev18__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 (150) hide show
  1. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/PKG-INFO +1 -1
  2. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/pyproject.toml +1 -1
  3. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/__init__.py +10 -0
  5. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/module_context.py +85 -39
  6. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/setup_types.py +42 -27
  7. digitalkin-0.3.2.dev18/src/digitalkin/models/module/tool_cache.py +227 -0
  8. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/tool_reference.py +36 -17
  9. digitalkin-0.3.2.dev18/src/digitalkin/models/services/registry.py +77 -0
  10. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/_base_module.py +6 -3
  11. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/grpc_registry.py +57 -0
  12. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/registry_strategy.py +6 -0
  13. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/__init__.py +1 -3
  14. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/dynamic_schema.py +4 -0
  15. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/schema_splitter.py +6 -0
  16. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin.egg-info/PKG-INFO +1 -1
  17. digitalkin-0.3.2.dev16/src/digitalkin/models/module/tool_cache.py +0 -68
  18. digitalkin-0.3.2.dev16/src/digitalkin/models/services/registry.py +0 -35
  19. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/LICENSE +0 -0
  20. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/README.md +0 -0
  21. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/__init__.py +0 -0
  22. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/mock/__init__.py +0 -0
  23. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/mock/mock_pb2.py +0 -0
  24. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  25. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/server_async_insecure.py +0 -0
  26. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/server_async_secure.py +0 -0
  27. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/server_sync_insecure.py +0 -0
  28. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/base_server/server_sync_secure.py +0 -0
  29. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/__init__.py +0 -0
  30. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/archetype_with_tools_module.py +0 -0
  31. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/cpu_intensive_module.py +0 -0
  32. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/dynamic_setup_module.py +0 -0
  33. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/minimal_llm_module.py +0 -0
  34. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/modules/text_transform_module.py +0 -0
  35. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  36. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  37. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  38. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  39. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  40. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/monitoring/tests/test_metrics.py +0 -0
  41. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/services/filesystem_module.py +0 -0
  42. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/examples/services/storage_module.py +0 -0
  43. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/setup.cfg +0 -0
  44. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/__init__.py +0 -0
  45. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/__init__.py +0 -0
  46. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/common/__init__.py +0 -0
  47. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/common/factories.py +0 -0
  48. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/job_manager/__init__.py +0 -0
  49. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  50. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  51. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
  52. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -0
  53. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/__init__.py +0 -0
  54. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  55. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  56. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  57. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/surrealdb_repository.py +0 -0
  58. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  59. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/core/task_manager/task_session.py +0 -0
  60. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/__init__.py +0 -0
  61. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  62. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/module_server.py +0 -0
  63. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/module_servicer.py +0 -0
  64. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  65. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
  66. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  67. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  68. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  69. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/logger.py +0 -0
  70. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/__init__.py +0 -0
  71. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/base_mixin.py +0 -0
  72. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/callback_mixin.py +0 -0
  73. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
  74. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/cost_mixin.py +0 -0
  75. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  76. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  77. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/logger_mixin.py +0 -0
  78. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/mixins/storage_mixin.py +0 -0
  79. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/__init__.py +0 -0
  80. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/core/__init__.py +0 -0
  81. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/core/job_manager_models.py +0 -0
  82. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/core/task_monitor.py +0 -0
  83. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  84. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/grpc_servers/models.py +0 -0
  85. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/grpc_servers/types.py +0 -0
  86. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/base_types.py +0 -0
  87. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/module.py +0 -0
  88. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/module_types.py +0 -0
  89. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/module/utility.py +0 -0
  90. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/services/__init__.py +0 -0
  91. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/services/cost.py +0 -0
  92. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/models/services/storage.py +0 -0
  93. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/__init__.py +0 -0
  94. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/archetype_module.py +0 -0
  95. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/tool_module.py +0 -0
  96. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/trigger_handler.py +0 -0
  97. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/triggers/__init__.py +0 -0
  98. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  99. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  100. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  101. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/py.typed +0 -0
  102. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/__init__.py +0 -0
  103. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/agent/__init__.py +0 -0
  104. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/agent/agent_strategy.py +0 -0
  105. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/agent/default_agent.py +0 -0
  106. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/base_strategy.py +0 -0
  107. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/communication/__init__.py +0 -0
  108. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  109. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/communication/default_communication.py +0 -0
  110. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  111. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/cost/__init__.py +0 -0
  112. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  113. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/cost/default_cost.py +0 -0
  114. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  115. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/filesystem/__init__.py +0 -0
  116. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  117. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  118. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  119. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/identity/__init__.py +0 -0
  120. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/identity/default_identity.py +0 -0
  121. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  122. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/__init__.py +0 -0
  123. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/default_registry.py +0 -0
  124. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/exceptions.py +0 -0
  125. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/registry/registry_models.py +0 -0
  126. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/services_config.py +0 -0
  127. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/services_models.py +0 -0
  128. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/setup/__init__.py +0 -0
  129. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/setup/default_setup.py +0 -0
  130. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  131. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  132. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/snapshot/__init__.py +0 -0
  133. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
  134. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
  135. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/storage/__init__.py +0 -0
  136. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/storage/default_storage.py +0 -0
  137. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  138. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  139. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/user_profile/__init__.py +0 -0
  140. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  141. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  142. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  143. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/arg_parser.py +0 -0
  144. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/development_mode_action.py +0 -0
  145. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  146. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin/utils/package_discover.py +0 -0
  147. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin.egg-info/SOURCES.txt +0 -0
  148. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  149. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin.egg-info/requires.txt +0 -0
  150. {digitalkin-0.3.2.dev16 → digitalkin-0.3.2.dev18}/src/digitalkin.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.3.2.dev16
3
+ Version: 0.3.2.dev18
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
@@ -12,7 +12,7 @@
12
12
 
13
13
  keywords = [ "digitalkin", "kin", "agent", "gprc", "sdk" ]
14
14
 
15
- version = "0.3.2.dev16"
15
+ version = "0.3.2.dev18"
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "0.3.2.dev16"
8
+ __version__ = "0.3.2.dev18"
@@ -6,6 +6,12 @@ from digitalkin.models.module.module_types import (
6
6
  DataTrigger,
7
7
  SetupModel,
8
8
  )
9
+ from digitalkin.models.module.tool_cache import (
10
+ ToolCache,
11
+ ToolDefinition,
12
+ ToolModuleInfo,
13
+ ToolParameter,
14
+ )
9
15
  from digitalkin.models.module.tool_reference import (
10
16
  ToolReference,
11
17
  ToolReferenceConfig,
@@ -25,6 +31,10 @@ __all__ = [
25
31
  "ModuleContext",
26
32
  "ModuleStartInfoOutput",
27
33
  "SetupModel",
34
+ "ToolCache",
35
+ "ToolDefinition",
36
+ "ToolModuleInfo",
37
+ "ToolParameter",
28
38
  "ToolReference",
29
39
  "ToolReferenceConfig",
30
40
  "ToolSelectionMode",
@@ -8,7 +8,7 @@ from typing import Any
8
8
  from zoneinfo import ZoneInfo
9
9
 
10
10
  from digitalkin.logger import logger
11
- from digitalkin.models.module.tool_cache import ToolCache
11
+ from digitalkin.models.module.tool_cache import ToolCache, ToolDefinition, ToolModuleInfo, ToolParameter
12
12
  from digitalkin.services.agent.agent_strategy import AgentStrategy
13
13
  from digitalkin.services.communication.communication_strategy import CommunicationStrategy
14
14
  from digitalkin.services.cost.cost_strategy import CostStrategy
@@ -227,74 +227,120 @@ class ModuleContext:
227
227
  llm_format=llm_format,
228
228
  )
229
229
 
230
- async def create_openai_style_tool(self, tool_name: str) -> dict[str, Any] | None:
231
- """Create OpenAI-style function calling schema for a tool.
230
+ async def create_openai_style_tools(self, module_id: str) -> list[dict[str, Any]]:
231
+ """Create OpenAI-style function calling schemas for a tool module.
232
232
 
233
- Uses tool cache (fast path) with registry fallback. Fetches the tool's
234
- input schema and wraps it in OpenAI function calling format.
233
+ Uses tool cache (fast path) with registry fallback. Returns one schema
234
+ per ToolDefinition (protocol) in the module.
235
235
 
236
236
  Args:
237
- tool_name: Module ID to look up (checks cache first, then registry).
237
+ module_id: Module ID to look up (checks cache first, then registry).
238
238
 
239
239
  Returns:
240
- OpenAI-style tool schema if found, None otherwise.
240
+ List of OpenAI-style tool schemas, one per protocol. Empty if not found.
241
241
  """
242
- module_info = self.tool_cache.get(tool_name, registry=self.registry)
243
- if not module_info:
244
- return None
245
-
246
- schemas = await self.communication.get_module_schemas(
247
- module_address=module_info.address,
248
- module_port=module_info.port,
249
- llm_format=True,
242
+ tool_module_info = await self.tool_cache.get(
243
+ module_id, registry=self.registry, communication=self.communication
250
244
  )
245
+ if not tool_module_info:
246
+ return []
247
+
248
+ return [
249
+ {
250
+ "type": "function",
251
+ "function": {
252
+ "module_id": tool_module_info.module_id,
253
+ "toolkit_name": tool_module_info.name or "undefined",
254
+ "name": tool_def.name,
255
+ "description": tool_def.description,
256
+ "parameters": ModuleContext._build_parameters_schema(tool_def.parameters),
257
+ },
258
+ }
259
+ for tool_def in tool_module_info.tools
260
+ ]
261
+
262
+ @staticmethod
263
+ def _build_parameters_schema(params: list[ToolParameter]) -> dict[str, Any]:
264
+ """Convert ToolParameter list to JSON Schema.
265
+
266
+ Args:
267
+ params: List of tool parameters.
251
268
 
269
+ Returns:
270
+ JSON Schema object with properties and required fields.
271
+ """
252
272
  return {
253
- "type": "function",
254
- "function": {
255
- "module_id": module_info.module_id,
256
- "name": module_info.name or "undefined",
257
- "description": module_info.documentation or "",
258
- "parameters": schemas["input"],
259
- },
273
+ "type": "object",
274
+ "properties": {p.name: {"type": p.type, "description": p.description or ""} for p in params},
275
+ "required": [p.name for p in params if p.required],
260
276
  }
261
277
 
262
- def create_tool_function(
278
+ def create_tool_functions(
263
279
  self,
264
280
  module_id: str,
265
- ) -> Callable[..., AsyncGenerator[dict, None]] | None:
266
- """Create async generator function for a tool.
281
+ ) -> list[tuple[ToolDefinition, Callable[..., AsyncGenerator[dict, None]]]]:
282
+ """Create tool functions for all protocols in a tool module.
283
+
284
+ Returns an async generator per ToolDefinition that calls the remote tool
285
+ module via gRPC with the protocol auto-injected.
267
286
 
268
- Returns an async generator that calls the remote tool module via gRPC
269
- and yields each response as it arrives until end_of_stream or gRPC ends.
287
+ This method only uses the tool cache (no registry fallback). Use this
288
+ in sync contexts like __init__ methods.
270
289
 
271
290
  Args:
272
- module_id: Module ID to look up (checks cache first, then registry).
291
+ module_id: Module ID to look up in cache.
273
292
 
274
293
  Returns:
275
- Async generator function if tool found, None otherwise.
294
+ List of (ToolDefinition, async_generator_function) tuples. Empty if not found.
276
295
  """
277
- module_info = self.tool_cache.get(module_id, registry=self.registry)
278
- if not module_info:
279
- return None
296
+ tool_module_info = self.tool_cache.entries.get(module_id)
297
+ if not tool_module_info:
298
+ return []
280
299
 
281
300
  communication = self.communication
282
301
  session = self.session
283
- address = module_info.address
284
- port = module_info.port
302
+
303
+ result = []
304
+ for tool_def in tool_module_info.tools:
305
+ # Capture tool_def in closure via separate method
306
+ fn = ModuleContext._create_single_tool_function(communication, session, tool_module_info, tool_def)
307
+ result.append((tool_def, fn))
308
+
309
+ return result
310
+
311
+ @staticmethod
312
+ def _create_single_tool_function(
313
+ communication: CommunicationStrategy,
314
+ session: Session,
315
+ tool_module_info: ToolModuleInfo,
316
+ tool_def: ToolDefinition,
317
+ ) -> Callable[..., AsyncGenerator[dict, None]]:
318
+ """Create a single tool function for a specific protocol.
319
+
320
+ Args:
321
+ communication: Communication strategy for gRPC calls.
322
+ session: Current session with setup_id and mission_id.
323
+ tool_module_info: Tool module information containing address and port.
324
+ tool_def: Tool definition with protocol name.
325
+
326
+ Returns:
327
+ Async generator function that calls the module with protocol injected.
328
+ """
329
+ protocol = tool_def.name
285
330
 
286
331
  async def tool_function(**kwargs: Any) -> AsyncGenerator[dict, None]: # noqa: ANN401
332
+ kwargs["protocol"] = protocol
287
333
  wrapped_input = {"root": kwargs}
288
334
  async for response in communication.call_module(
289
- module_address=address,
290
- module_port=port,
335
+ module_address=tool_module_info.address,
336
+ module_port=tool_module_info.port,
291
337
  input_data=wrapped_input,
292
- setup_id=session.setup_id,
338
+ setup_id=tool_module_info.setup_id,
293
339
  mission_id=session.mission_id,
294
340
  ):
295
341
  yield response
296
342
 
297
- tool_function.__name__ = module_info.name or module_info.module_id
298
- tool_function.__doc__ = module_info.documentation or ""
343
+ tool_function.__name__ = tool_def.name
344
+ tool_function.__doc__ = tool_def.description
299
345
 
300
346
  return tool_function
@@ -8,9 +8,8 @@ from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeVar, cast, get_arg
8
8
  from pydantic import BaseModel, ConfigDict, Field, create_model
9
9
 
10
10
  from digitalkin.logger import logger
11
- from digitalkin.models.module.tool_cache import ToolCache
11
+ from digitalkin.models.module.tool_cache import ToolCache, ToolModuleInfo
12
12
  from digitalkin.models.module.tool_reference import ToolReference
13
- from digitalkin.models.services.registry import ModuleInfo
14
13
  from digitalkin.utils.dynamic_schema import (
15
14
  DynamicField,
16
15
  get_fetchers,
@@ -21,6 +20,7 @@ from digitalkin.utils.dynamic_schema import (
21
20
  if TYPE_CHECKING:
22
21
  from pydantic.fields import FieldInfo
23
22
 
23
+ from digitalkin.services.communication import CommunicationStrategy
24
24
  from digitalkin.services.registry import RegistryStrategy
25
25
 
26
26
  SetupModelT = TypeVar("SetupModelT", bound="SetupModel")
@@ -53,14 +53,14 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
53
53
  # Check if it's a list type
54
54
  origin = get_origin(annotation)
55
55
  if origin is list:
56
- new_annotations[cache_field_name] = list[ModuleInfo]
56
+ new_annotations[cache_field_name] = list[ToolModuleInfo]
57
57
  setattr(
58
58
  cls,
59
59
  cache_field_name,
60
60
  Field(default_factory=list, json_schema_extra={"hidden": True}),
61
61
  )
62
62
  else:
63
- new_annotations[cache_field_name] = ModuleInfo | None
63
+ new_annotations[cache_field_name] = ToolModuleInfo | None
64
64
  setattr(
65
65
  cls,
66
66
  cache_field_name,
@@ -336,39 +336,45 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
336
336
 
337
337
  return new_field_info
338
338
 
339
- def resolve_tool_references(self, registry: "RegistryStrategy") -> None:
339
+ async def resolve_tool_references(
340
+ self, registry: "RegistryStrategy", communication: "CommunicationStrategy"
341
+ ) -> None:
340
342
  """Resolve all ToolReference fields recursively.
341
343
 
342
344
  Args:
343
345
  registry: Registry service for module discovery.
346
+ communication: Communication service for module schemas.
344
347
  """
345
348
  logger.info("Starting resolve_tool_references")
346
- self._resolve_tool_references_recursive(self, registry)
349
+ await self._resolve_tool_references_recursive(self, registry, communication)
347
350
  logger.info("Finished resolve_tool_references")
348
351
 
349
352
  @classmethod
350
- def _resolve_tool_references_recursive(
353
+ async def _resolve_tool_references_recursive(
351
354
  cls,
352
355
  model_instance: BaseModel,
353
356
  registry: "RegistryStrategy",
357
+ communication: "CommunicationStrategy",
354
358
  ) -> None:
355
359
  """Recursively resolve ToolReference fields in a model.
356
360
 
357
361
  Args:
358
362
  model_instance: Model instance to process.
359
363
  registry: Registry service for resolution.
364
+ communication: Communication service for module schemas.
360
365
  """
361
366
  for field_name, field_value in model_instance.__dict__.items():
362
367
  if field_value is None:
363
368
  continue
364
- cls._resolve_field_value(field_name, field_value, registry)
369
+ await cls._resolve_field_value(field_name, field_value, registry, communication)
365
370
 
366
371
  @classmethod
367
- def _resolve_field_value(
372
+ async def _resolve_field_value(
368
373
  cls,
369
374
  field_name: str,
370
375
  field_value: "BaseModel | ToolReference | list | dict",
371
376
  registry: "RegistryStrategy",
377
+ communication: "CommunicationStrategy",
372
378
  ) -> None:
373
379
  """Resolve a single field value based on its type.
374
380
 
@@ -376,22 +382,24 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
376
382
  field_name: Name of the field.
377
383
  field_value: Value to process.
378
384
  registry: Registry service for resolution.
385
+ communication: Communication service for module schemas.
379
386
  """
380
387
  if isinstance(field_value, ToolReference):
381
- cls._resolve_single_tool_reference(field_name, field_value, registry)
388
+ await cls._resolve_single_tool_reference(field_name, field_value, registry, communication)
382
389
  elif isinstance(field_value, BaseModel):
383
- cls._resolve_tool_references_recursive(field_value, registry)
390
+ await cls._resolve_tool_references_recursive(field_value, registry, communication)
384
391
  elif isinstance(field_value, list):
385
- cls._resolve_list_items(field_value, registry)
392
+ await cls._resolve_list_items(field_value, registry, communication)
386
393
  elif isinstance(field_value, dict):
387
- cls._resolve_dict_values(field_value, registry)
394
+ await cls._resolve_dict_values(field_value, registry, communication)
388
395
 
389
396
  @classmethod
390
- def _resolve_single_tool_reference(
397
+ async def _resolve_single_tool_reference(
391
398
  cls,
392
399
  field_name: str,
393
400
  tool_ref: ToolReference,
394
401
  registry: "RegistryStrategy",
402
+ communication: "CommunicationStrategy",
395
403
  ) -> None:
396
404
  """Resolve a single ToolReference.
397
405
 
@@ -399,47 +407,54 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
399
407
  field_name: Name of the field for logging.
400
408
  tool_ref: ToolReference to resolve.
401
409
  registry: Registry service for resolution.
410
+ communication: Communication service for module schemas.
402
411
  """
403
- logger.info("Resolving ToolReference '%s' with module_id='%s'", field_name, tool_ref.config.module_id)
412
+ logger.info("Resolving ToolReference '%s' with setup_id='%s'", field_name, tool_ref.config.setup_id)
404
413
  try:
405
- tool_ref.resolve(registry)
406
- logger.info("Resolved ToolReference '%s' -> %s", field_name, tool_ref.module_info)
414
+ await tool_ref.resolve(registry, communication)
415
+ logger.info("Resolved ToolReference '%s' -> %s", field_name, tool_ref.tool_module_info)
407
416
  except Exception:
408
417
  logger.exception("Failed to resolve ToolReference '%s'", field_name)
409
418
 
410
419
  @classmethod
411
- def _resolve_list_items(cls, items: list, registry: "RegistryStrategy") -> None:
420
+ async def _resolve_list_items(
421
+ cls, items: list, registry: "RegistryStrategy", communication: "CommunicationStrategy"
422
+ ) -> None:
412
423
  """Resolve ToolReference instances in a list.
413
424
 
414
425
  Args:
415
426
  items: List of items to process.
416
427
  registry: Registry service for resolution.
428
+ communication: Communication service for module schemas.
417
429
  """
418
430
  for item in items:
419
431
  if isinstance(item, ToolReference):
420
- cls._resolve_single_tool_reference("list_item", item, registry)
432
+ await cls._resolve_single_tool_reference("list_item", item, registry, communication)
421
433
  elif isinstance(item, BaseModel):
422
- cls._resolve_tool_references_recursive(item, registry)
434
+ await cls._resolve_tool_references_recursive(item, registry, communication)
423
435
 
424
436
  @classmethod
425
- def _resolve_dict_values(cls, mapping: dict, registry: "RegistryStrategy") -> None:
437
+ async def _resolve_dict_values(
438
+ cls, mapping: dict, registry: "RegistryStrategy", communication: "CommunicationStrategy"
439
+ ) -> None:
426
440
  """Resolve ToolReference instances in dict values.
427
441
 
428
442
  Args:
429
443
  mapping: Dict to process.
430
444
  registry: Registry service for resolution.
445
+ communication: Communication service for module schemas.
431
446
  """
432
447
  for item in mapping.values():
433
448
  if isinstance(item, ToolReference):
434
- cls._resolve_single_tool_reference("dict_value", item, registry)
449
+ await cls._resolve_single_tool_reference("dict_value", item, registry, communication)
435
450
  elif isinstance(item, BaseModel):
436
- cls._resolve_tool_references_recursive(item, registry)
451
+ await cls._resolve_tool_references_recursive(item, registry, communication)
437
452
 
438
453
  def build_tool_cache(self) -> ToolCache:
439
454
  """Build tool cache from resolved ToolReferences, populating companion fields.
440
455
 
441
456
  Returns:
442
- ToolCache with field names as keys and ModuleInfo as values.
457
+ ToolCache with field names as keys and ToolModuleInfo as values.
443
458
  """
444
459
  logger.info("Building tool cache")
445
460
  cache = ToolCache()
@@ -461,7 +476,7 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
461
476
  cache_field_name = f"{field_name}_cache"
462
477
 
463
478
  cached_info = getattr(model_instance, cache_field_name, None)
464
- module_info = field_value.module_info or cached_info
479
+ module_info = field_value.tool_module_info or cached_info
465
480
  if module_info:
466
481
  if not cached_info:
467
482
  setattr(model_instance, cache_field_name, module_info)
@@ -472,12 +487,12 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
472
487
  elif isinstance(field_value, list):
473
488
  cache_field_name = f"{field_name}_cache"
474
489
  cached_infos = getattr(model_instance, cache_field_name, None) or []
475
- resolved_infos: list[ModuleInfo] = []
490
+ resolved_infos: list[ToolModuleInfo] = []
476
491
 
477
492
  for idx, item in enumerate(field_value):
478
493
  if isinstance(item, ToolReference):
479
494
  # Use resolved info or fallback to cached
480
- module_info = item.module_info or (cached_infos[idx] if idx < len(cached_infos) else None)
495
+ module_info = item.tool_module_info or (cached_infos[idx] if idx < len(cached_infos) else None)
481
496
  if module_info:
482
497
  resolved_infos.append(module_info)
483
498
  cache.add(module_info.module_id, module_info)
@@ -0,0 +1,227 @@
1
+ """Tool cache for resolved tool references."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from digitalkin.logger import logger
8
+ from digitalkin.models.services.registry import ModuleInfo
9
+ from digitalkin.services.registry import RegistryStrategy
10
+
11
+ if TYPE_CHECKING:
12
+ from digitalkin.services.communication import CommunicationStrategy
13
+
14
+
15
+ class ToolParameter(BaseModel):
16
+ """Definition of a single tool parameter.
17
+
18
+ Attributes:
19
+ name: Parameter name.
20
+ type: JSON Schema type (string, integer, number, boolean, array, object).
21
+ description: Parameter description for the LLM.
22
+ required: Whether this parameter is required.
23
+ enum: Optional list of allowed values.
24
+ items: Optional schema for array item types.
25
+ properties: Optional schema for object properties.
26
+ """
27
+
28
+ name: str
29
+ type: str
30
+ description: str
31
+ required: bool = True
32
+ enum: list[str] | None = None
33
+ items: dict[str, Any] | None = None
34
+ properties: dict[str, Any] | None = None
35
+
36
+
37
+ class ToolDefinition(BaseModel):
38
+ """Complete definition of an LLM tool with grouped parameters.
39
+
40
+ Attributes:
41
+ name: Tool name (from protocol const or trigger class name).
42
+ description: Tool description (from trigger docstring).
43
+ parameters: List of parameter definitions.
44
+ """
45
+
46
+ name: str
47
+ description: str
48
+ parameters: list[ToolParameter] = Field(default_factory=list)
49
+
50
+
51
+ class ToolModuleInfo(ModuleInfo):
52
+ """Module info for tool modules."""
53
+
54
+ tools: list[ToolDefinition]
55
+ setup_id: str
56
+
57
+
58
+ class ToolCache(BaseModel):
59
+ """Registry cache storing resolved tool references by setup field name."""
60
+
61
+ entries: dict[str, ToolModuleInfo] = Field(default_factory=dict)
62
+
63
+ def add(self, setup_id: str, tool_module_info: ToolModuleInfo) -> None:
64
+ """Add a tool to the cache.
65
+
66
+ Args:
67
+ setup_id: Field name from SetupModel used as cache key.
68
+ tool_module_info: Resolved tool module information.
69
+ """
70
+ self.entries[setup_id] = tool_module_info
71
+ logger.debug(
72
+ "Tool cached",
73
+ extra={"setup_id": setup_id, "module_id": tool_module_info.module_id},
74
+ )
75
+
76
+ async def get(
77
+ self,
78
+ setup_id: str,
79
+ *,
80
+ registry: RegistryStrategy | None = None,
81
+ communication: "CommunicationStrategy | None" = None,
82
+ ) -> ToolModuleInfo | None:
83
+ """Get a tool from cache, optionally querying registry on miss.
84
+
85
+ Args:
86
+ setup_id: Field name to look up.
87
+ registry: Optional registry to query on cache miss.
88
+ communication: Optional communication strategy for schema fetching.
89
+
90
+ Returns:
91
+ ToolModuleInfo if found, None otherwise.
92
+ """
93
+ cached = self.entries.get(setup_id)
94
+ if cached:
95
+ return cached
96
+
97
+ if registry and communication:
98
+ try:
99
+ setup_info = registry.get_setup(setup_id)
100
+ if setup_info and setup_info.module_id:
101
+ info = registry.discover_by_id(setup_info.module_id)
102
+ if info:
103
+ tool_info = await module_info_to_tool_module_info(info, setup_id, communication)
104
+ self.add(setup_id, tool_info)
105
+ return tool_info
106
+ except Exception:
107
+ logger.exception("Registry lookup failed", extra={"setup_id": setup_id})
108
+
109
+ return None
110
+
111
+ def clear(self) -> None:
112
+ """Clear all cache entries."""
113
+ self.entries.clear()
114
+
115
+ def list_tools(self) -> list[str]:
116
+ """List all cached tool names.
117
+
118
+ Returns:
119
+ List of setup field names in cache.
120
+ """
121
+ return list(self.entries.keys())
122
+
123
+
124
+ async def module_info_to_tool_module_info(
125
+ module_info: ModuleInfo,
126
+ setup_id: str,
127
+ communication: "CommunicationStrategy",
128
+ *,
129
+ llm_format: bool = True,
130
+ ) -> ToolModuleInfo:
131
+ """Convert ModuleInfo to ToolModuleInfo by fetching schemas via gRPC.
132
+
133
+ Fetches the module's input schema and extracts tool definitions from
134
+ the discriminated union structure.
135
+
136
+ Args:
137
+ module_info: Module info from registry.
138
+ setup_id: Setup ID from tool configuration.
139
+ communication: Communication strategy for gRPC calls.
140
+ llm_format: Use LLM-friendly schema format.
141
+
142
+ Returns:
143
+ ToolModuleInfo with tools extracted from input schema.
144
+ """
145
+ schemas = await communication.get_module_schemas(
146
+ module_info.address,
147
+ module_info.port,
148
+ llm_format=llm_format,
149
+ )
150
+
151
+ input_schema = schemas.get("input", {})
152
+ if llm_format:
153
+ input_schema = input_schema.get("json_schema", input_schema)
154
+
155
+ tools = _extract_tools_from_schema(input_schema)
156
+
157
+ return ToolModuleInfo(
158
+ module_id=module_info.module_id,
159
+ module_type=module_info.module_type,
160
+ address=module_info.address,
161
+ port=module_info.port,
162
+ version=module_info.version,
163
+ name=module_info.name,
164
+ documentation=module_info.documentation,
165
+ status=module_info.status,
166
+ tools=tools,
167
+ setup_id=setup_id,
168
+ )
169
+
170
+
171
+ def _extract_tools_from_schema(schema: dict[str, Any]) -> list[ToolDefinition]:
172
+ """Extract tool definitions from a discriminated union input schema.
173
+
174
+ Args:
175
+ schema: JSON schema with $defs containing protocol-based types.
176
+
177
+ Returns:
178
+ List of ToolDefinition with parameters grouped by trigger.
179
+ """
180
+ tools: list[ToolDefinition] = []
181
+ defs = schema.get("$defs", {})
182
+
183
+ # Skip SDK utility protocols
184
+ utility_protocols = {"HealthcheckPingInput", "HealthcheckServicesInput", "HealthcheckStatusInput"}
185
+
186
+ for def_name, def_schema in defs.items():
187
+ if def_name in utility_protocols:
188
+ continue
189
+
190
+ properties = def_schema.get("properties", {})
191
+ protocol_prop = properties.get("protocol", {})
192
+
193
+ # Skip if no protocol const (not a tool input type)
194
+ if "const" not in protocol_prop:
195
+ continue
196
+
197
+ # Extract tool-level info from trigger
198
+ tool_name = protocol_prop.get("const", def_name)
199
+ tool_description = def_schema.get("description", "")
200
+
201
+ required_fields = set(def_schema.get("required", []))
202
+ parameters: list[ToolParameter] = []
203
+
204
+ for prop_name, prop_info in properties.items():
205
+ if prop_name in {"protocol", "created_at"}:
206
+ continue
207
+
208
+ param = ToolParameter(
209
+ name=prop_name,
210
+ type=prop_info.get("type", "string"),
211
+ description=prop_info.get("description", ""),
212
+ required=prop_name in required_fields,
213
+ enum=prop_info.get("enum"),
214
+ items=prop_info.get("items"),
215
+ properties=prop_info.get("properties"),
216
+ )
217
+ parameters.append(param)
218
+
219
+ tools.append(
220
+ ToolDefinition(
221
+ name=tool_name,
222
+ description=tool_description,
223
+ parameters=parameters,
224
+ )
225
+ )
226
+
227
+ return tools