digitalkin 0.3.2.dev17__tar.gz → 0.3.2.dev19__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 (149) hide show
  1. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/PKG-INFO +1 -1
  2. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/pyproject.toml +1 -1
  3. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/__version__.py +1 -1
  4. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/module_servicer.py +27 -2
  5. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/module_context.py +10 -14
  6. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/setup_types.py +141 -102
  7. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/tool_cache.py +15 -11
  8. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/tool_reference.py +4 -2
  9. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/_base_module.py +1 -15
  10. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/__init__.py +14 -0
  11. digitalkin-0.3.2.dev19/src/digitalkin/utils/conditional_schema.py +260 -0
  12. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/schema_splitter.py +6 -0
  13. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin.egg-info/PKG-INFO +1 -1
  14. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin.egg-info/SOURCES.txt +1 -0
  15. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/LICENSE +0 -0
  16. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/README.md +0 -0
  17. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/__init__.py +0 -0
  18. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/mock/__init__.py +0 -0
  19. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/mock/mock_pb2.py +0 -0
  20. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  21. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/server_async_insecure.py +0 -0
  22. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/server_async_secure.py +0 -0
  23. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/server_sync_insecure.py +0 -0
  24. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/base_server/server_sync_secure.py +0 -0
  25. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/__init__.py +0 -0
  26. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/archetype_with_tools_module.py +0 -0
  27. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/cpu_intensive_module.py +0 -0
  28. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/dynamic_setup_module.py +0 -0
  29. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/minimal_llm_module.py +0 -0
  30. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/modules/text_transform_module.py +0 -0
  31. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/digitalkin_observability/__init__.py +0 -0
  32. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/digitalkin_observability/http_server.py +0 -0
  33. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/digitalkin_observability/interceptors.py +0 -0
  34. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/digitalkin_observability/metrics.py +0 -0
  35. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/digitalkin_observability/prometheus.py +0 -0
  36. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/monitoring/tests/test_metrics.py +0 -0
  37. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/services/filesystem_module.py +0 -0
  38. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/examples/services/storage_module.py +0 -0
  39. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/setup.cfg +0 -0
  40. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/__init__.py +0 -0
  41. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/__init__.py +0 -0
  42. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/common/__init__.py +0 -0
  43. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/common/factories.py +0 -0
  44. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/job_manager/__init__.py +0 -0
  45. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  46. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  47. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
  48. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -0
  49. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/__init__.py +0 -0
  50. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  51. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  52. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  53. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/surrealdb_repository.py +0 -0
  54. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  55. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/core/task_manager/task_session.py +0 -0
  56. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/__init__.py +0 -0
  57. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  58. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/module_server.py +0 -0
  59. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  60. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
  61. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +0 -0
  62. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  63. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +0 -0
  64. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/logger.py +0 -0
  65. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/__init__.py +0 -0
  66. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/base_mixin.py +0 -0
  67. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/callback_mixin.py +0 -0
  68. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
  69. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/cost_mixin.py +0 -0
  70. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  71. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  72. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/logger_mixin.py +0 -0
  73. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/mixins/storage_mixin.py +0 -0
  74. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/__init__.py +0 -0
  75. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/core/__init__.py +0 -0
  76. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/core/job_manager_models.py +0 -0
  77. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/core/task_monitor.py +0 -0
  78. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  79. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/grpc_servers/models.py +0 -0
  80. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/grpc_servers/types.py +0 -0
  81. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/__init__.py +0 -0
  82. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/base_types.py +0 -0
  83. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/module.py +0 -0
  84. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/module_types.py +0 -0
  85. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/module/utility.py +0 -0
  86. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/services/__init__.py +0 -0
  87. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/services/cost.py +0 -0
  88. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/services/registry.py +0 -0
  89. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/models/services/storage.py +0 -0
  90. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/__init__.py +0 -0
  91. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/archetype_module.py +0 -0
  92. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/tool_module.py +0 -0
  93. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/trigger_handler.py +0 -0
  94. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/triggers/__init__.py +0 -0
  95. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  96. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  97. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  98. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/py.typed +0 -0
  99. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/__init__.py +0 -0
  100. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/agent/__init__.py +0 -0
  101. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/agent/agent_strategy.py +0 -0
  102. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/agent/default_agent.py +0 -0
  103. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/base_strategy.py +0 -0
  104. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/communication/__init__.py +0 -0
  105. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  106. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/communication/default_communication.py +0 -0
  107. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  108. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/cost/__init__.py +0 -0
  109. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  110. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/cost/default_cost.py +0 -0
  111. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  112. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/filesystem/__init__.py +0 -0
  113. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  114. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  115. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  116. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/identity/__init__.py +0 -0
  117. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/identity/default_identity.py +0 -0
  118. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  119. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/__init__.py +0 -0
  120. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/default_registry.py +0 -0
  121. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/exceptions.py +0 -0
  122. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/grpc_registry.py +0 -0
  123. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/registry_models.py +0 -0
  124. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/registry/registry_strategy.py +0 -0
  125. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/services_config.py +0 -0
  126. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/services_models.py +0 -0
  127. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/setup/__init__.py +0 -0
  128. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/setup/default_setup.py +0 -0
  129. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  130. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  131. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/snapshot/__init__.py +0 -0
  132. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
  133. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
  134. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/storage/__init__.py +0 -0
  135. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/storage/default_storage.py +0 -0
  136. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  137. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  138. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/user_profile/__init__.py +0 -0
  139. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  140. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  141. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  142. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/arg_parser.py +0 -0
  143. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/development_mode_action.py +0 -0
  144. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/dynamic_schema.py +0 -0
  145. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  146. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin/utils/package_discover.py +0 -0
  147. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  148. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/src/digitalkin.egg-info/requires.txt +0 -0
  149. {digitalkin-0.3.2.dev17 → digitalkin-0.3.2.dev19}/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.dev17
3
+ Version: 0.3.2.dev19
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.dev17"
15
+ version = "0.3.2.dev19"
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.dev17"
8
+ __version__ = "0.3.2.dev19"
@@ -17,7 +17,7 @@ from digitalkin.core.job_manager.base_job_manager import BaseJobManager
17
17
  from digitalkin.grpc_servers.utils.exceptions import ServicerError
18
18
  from digitalkin.logger import logger
19
19
  from digitalkin.models.core.job_manager_models import JobManagerMode
20
- from digitalkin.models.module.module import ModuleStatus
20
+ from digitalkin.models.module.module import ModuleCodeModel, ModuleStatus
21
21
  from digitalkin.modules._base_module import BaseModule
22
22
  from digitalkin.services.registry import GrpcRegistry, RegistryStrategy
23
23
  from digitalkin.services.services_models import ServicesMode
@@ -159,7 +159,32 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
159
159
  return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
160
160
 
161
161
  updated_setup_data = await self.job_manager.generate_config_setup_module_response(job_id)
162
- logger.info("Setup updated", extra={"job_id": job_id})
162
+ logger.info("Setup response received", extra={"job_id": job_id})
163
+
164
+ # Check if response is an error
165
+ if isinstance(updated_setup_data, ModuleCodeModel):
166
+ logger.error(
167
+ "Config setup failed",
168
+ extra={"job_id": job_id, "code": updated_setup_data.code, "message": updated_setup_data.message},
169
+ )
170
+ context.set_code(grpc.StatusCode.INTERNAL)
171
+ context.set_details(updated_setup_data.message or "Config setup failed")
172
+ return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
173
+
174
+ if isinstance(updated_setup_data, dict) and "code" in updated_setup_data:
175
+ # ModuleCodeModel was serialized to dict
176
+ logger.error(
177
+ "Config setup failed",
178
+ extra={
179
+ "job_id": job_id,
180
+ "code": updated_setup_data["code"],
181
+ "message": updated_setup_data.get("message"),
182
+ },
183
+ )
184
+ context.set_code(grpc.StatusCode.INTERNAL)
185
+ context.set_details(updated_setup_data.get("message") or "Config setup failed")
186
+ return lifecycle_pb2.ConfigSetupModuleResponse(success=False)
187
+
163
188
  logger.debug("Updated setup data", extra={"job_id": job_id, "setup_data": updated_setup_data})
164
189
  setup_version.content = json_format.ParseDict(
165
190
  updated_setup_data,
@@ -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, ToolDefinition, ToolParameter
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,20 +227,20 @@ class ModuleContext:
227
227
  llm_format=llm_format,
228
228
  )
229
229
 
230
- async def create_openai_style_tools(self, tool_name: str) -> list[dict[str, Any]]:
230
+ async def create_openai_style_tools(self, module_id: str) -> list[dict[str, Any]]:
231
231
  """Create OpenAI-style function calling schemas for a tool module.
232
232
 
233
233
  Uses tool cache (fast path) with registry fallback. Returns one schema
234
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
240
  List of OpenAI-style tool schemas, one per protocol. Empty if not found.
241
241
  """
242
242
  tool_module_info = await self.tool_cache.get(
243
- tool_name, registry=self.registry, communication=self.communication
243
+ module_id, registry=self.registry, communication=self.communication
244
244
  )
245
245
  if not tool_module_info:
246
246
  return []
@@ -299,13 +299,11 @@ class ModuleContext:
299
299
 
300
300
  communication = self.communication
301
301
  session = self.session
302
- address = tool_module_info.address
303
- port = tool_module_info.port
304
302
 
305
303
  result = []
306
304
  for tool_def in tool_module_info.tools:
307
305
  # Capture tool_def in closure via separate method
308
- fn = ModuleContext._create_single_tool_function(communication, session, address, port, tool_def)
306
+ fn = ModuleContext._create_single_tool_function(communication, session, tool_module_info, tool_def)
309
307
  result.append((tool_def, fn))
310
308
 
311
309
  return result
@@ -314,8 +312,7 @@ class ModuleContext:
314
312
  def _create_single_tool_function(
315
313
  communication: CommunicationStrategy,
316
314
  session: Session,
317
- address: str,
318
- port: int,
315
+ tool_module_info: ToolModuleInfo,
319
316
  tool_def: ToolDefinition,
320
317
  ) -> Callable[..., AsyncGenerator[dict, None]]:
321
318
  """Create a single tool function for a specific protocol.
@@ -323,8 +320,7 @@ class ModuleContext:
323
320
  Args:
324
321
  communication: Communication strategy for gRPC calls.
325
322
  session: Current session with setup_id and mission_id.
326
- address: Module address.
327
- port: Module port.
323
+ tool_module_info: Tool module information containing address and port.
328
324
  tool_def: Tool definition with protocol name.
329
325
 
330
326
  Returns:
@@ -336,10 +332,10 @@ class ModuleContext:
336
332
  kwargs["protocol"] = protocol
337
333
  wrapped_input = {"root": kwargs}
338
334
  async for response in communication.call_module(
339
- module_address=address,
340
- module_port=port,
335
+ module_address=tool_module_info.address,
336
+ module_port=tool_module_info.port,
341
337
  input_data=wrapped_input,
342
- setup_id=session.setup_id,
338
+ setup_id=tool_module_info.setup_id,
343
339
  mission_id=session.mission_id,
344
340
  ):
345
341
  yield response
@@ -29,65 +29,12 @@ SetupModelT = TypeVar("SetupModelT", bound="SetupModel")
29
29
  class SetupModel(BaseModel, Generic[SetupModelT]):
30
30
  """Base setup model with dynamic schema and tool cache support."""
31
31
 
32
+ model_config = ConfigDict(extra="allow")
32
33
  _clean_model_cache: ClassVar[dict[tuple[type, bool, bool], type]] = {}
33
-
34
- def __init_subclass__(cls, **kwargs: Any) -> None: # noqa: ANN401
35
- """Inject hidden companion fields for ToolReference annotations.
36
-
37
- Args:
38
- **kwargs: Keyword arguments passed to parent.
39
- """
40
- super().__init_subclass__(**kwargs)
41
- cls._inject_tool_cache_fields()
42
-
43
- @classmethod
44
- def _inject_tool_cache_fields(cls) -> None:
45
- """Inject hidden companion fields for ToolReference annotations."""
46
- annotations = getattr(cls, "__annotations__", {})
47
- new_annotations: dict[str, Any] = {}
48
-
49
- for field_name, annotation in annotations.items():
50
- if cls._is_tool_reference_annotation(annotation):
51
- cache_field_name = f"{field_name}_cache"
52
- if cache_field_name not in annotations:
53
- # Check if it's a list type
54
- origin = get_origin(annotation)
55
- if origin is list:
56
- new_annotations[cache_field_name] = list[ToolModuleInfo]
57
- setattr(
58
- cls,
59
- cache_field_name,
60
- Field(default_factory=list, json_schema_extra={"hidden": True}),
61
- )
62
- else:
63
- new_annotations[cache_field_name] = ToolModuleInfo | None
64
- setattr(
65
- cls,
66
- cache_field_name,
67
- Field(default=None, json_schema_extra={"hidden": True}),
68
- )
69
-
70
- if new_annotations:
71
- cls.__annotations__ = {**annotations, **new_annotations}
72
-
73
- @classmethod
74
- def _is_tool_reference_annotation(cls, annotation: object) -> bool:
75
- """Check if annotation is ToolReference or Optional[ToolReference].
76
-
77
- Args:
78
- annotation: Type annotation to check.
79
-
80
- Returns:
81
- True if annotation is or contains ToolReference.
82
- """
83
- origin = get_origin(annotation)
84
- if origin is typing.Union or origin is types.UnionType:
85
- return any(
86
- arg is ToolReference or (isinstance(arg, type) and issubclass(arg, ToolReference))
87
- for arg in get_args(annotation)
88
- if arg is not type(None)
89
- )
90
- return annotation is ToolReference or (isinstance(annotation, type) and issubclass(annotation, ToolReference))
34
+ resolved_tools: dict[str, ToolModuleInfo] = Field(
35
+ default_factory=dict,
36
+ json_schema_extra={"hidden": True},
37
+ )
91
38
 
92
39
  @classmethod
93
40
  async def get_clean_model(
@@ -285,7 +232,7 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
285
232
  if not has_changes:
286
233
  return model_cls
287
234
 
288
- root_extra = cls.model_config.get("json_schema_extra", {})
235
+ root_extra = model_cls.model_config.get("json_schema_extra", {})
289
236
 
290
237
  return create_model(
291
238
  model_cls.__name__,
@@ -346,7 +293,12 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
346
293
  communication: Communication service for module schemas.
347
294
  """
348
295
  logger.info("Starting resolve_tool_references")
349
- await self._resolve_tool_references_recursive(self, registry, communication)
296
+ await self._resolve_tool_references_recursive(
297
+ self,
298
+ registry,
299
+ communication,
300
+ self.resolved_tools,
301
+ )
350
302
  logger.info("Finished resolve_tool_references")
351
303
 
352
304
  @classmethod
@@ -355,6 +307,7 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
355
307
  model_instance: BaseModel,
356
308
  registry: "RegistryStrategy",
357
309
  communication: "CommunicationStrategy",
310
+ resolved_tools: dict[str, ToolModuleInfo],
358
311
  ) -> None:
359
312
  """Recursively resolve ToolReference fields in a model.
360
313
 
@@ -362,11 +315,18 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
362
315
  model_instance: Model instance to process.
363
316
  registry: Registry service for resolution.
364
317
  communication: Communication service for module schemas.
318
+ resolved_tools: Cache of already resolved tools.
365
319
  """
366
320
  for field_name, field_value in model_instance.__dict__.items():
367
321
  if field_value is None:
368
322
  continue
369
- await cls._resolve_field_value(field_name, field_value, registry, communication)
323
+ await cls._resolve_field_value(
324
+ field_name,
325
+ field_value,
326
+ registry,
327
+ communication,
328
+ resolved_tools,
329
+ )
370
330
 
371
331
  @classmethod
372
332
  async def _resolve_field_value(
@@ -375,6 +335,7 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
375
335
  field_value: "BaseModel | ToolReference | list | dict",
376
336
  registry: "RegistryStrategy",
377
337
  communication: "CommunicationStrategy",
338
+ resolved_tools: dict[str, ToolModuleInfo],
378
339
  ) -> None:
379
340
  """Resolve a single field value based on its type.
380
341
 
@@ -383,15 +344,37 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
383
344
  field_value: Value to process.
384
345
  registry: Registry service for resolution.
385
346
  communication: Communication service for module schemas.
347
+ resolved_tools: Cache of already resolved tools.
386
348
  """
387
349
  if isinstance(field_value, ToolReference):
388
- await cls._resolve_single_tool_reference(field_name, field_value, registry, communication)
350
+ await cls._resolve_single_tool_reference(
351
+ field_name,
352
+ field_value,
353
+ registry,
354
+ communication,
355
+ resolved_tools,
356
+ )
389
357
  elif isinstance(field_value, BaseModel):
390
- await cls._resolve_tool_references_recursive(field_value, registry, communication)
358
+ await cls._resolve_tool_references_recursive(
359
+ field_value,
360
+ registry,
361
+ communication,
362
+ resolved_tools,
363
+ )
391
364
  elif isinstance(field_value, list):
392
- await cls._resolve_list_items(field_value, registry, communication)
365
+ await cls._resolve_list_items(
366
+ field_value,
367
+ registry,
368
+ communication,
369
+ resolved_tools,
370
+ )
393
371
  elif isinstance(field_value, dict):
394
- await cls._resolve_dict_values(field_value, registry, communication)
372
+ await cls._resolve_dict_values(
373
+ field_value,
374
+ registry,
375
+ communication,
376
+ resolved_tools,
377
+ )
395
378
 
396
379
  @classmethod
397
380
  async def _resolve_single_tool_reference(
@@ -400,6 +383,7 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
400
383
  tool_ref: ToolReference,
401
384
  registry: "RegistryStrategy",
402
385
  communication: "CommunicationStrategy",
386
+ resolved_tools: dict[str, ToolModuleInfo],
403
387
  ) -> None:
404
388
  """Resolve a single ToolReference.
405
389
 
@@ -408,17 +392,33 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
408
392
  tool_ref: ToolReference to resolve.
409
393
  registry: Registry service for resolution.
410
394
  communication: Communication service for module schemas.
395
+ resolved_tools: Cache of already resolved tools.
411
396
  """
412
397
  logger.info("Resolving ToolReference '%s' with setup_id='%s'", field_name, tool_ref.config.setup_id)
398
+
399
+ slug = tool_ref.slug
400
+ if slug:
401
+ cached = resolved_tools.get(slug)
402
+ if cached:
403
+ tool_ref._cached_info = cached # noqa: SLF001
404
+ logger.info("ToolReference '%s' resolved from cache -> %s", field_name, cached)
405
+ return
406
+
413
407
  try:
414
- await tool_ref.resolve(registry, communication)
408
+ info = await tool_ref.resolve(registry, communication)
409
+ if info and info.setup_id:
410
+ resolved_tools[info.setup_id] = info
415
411
  logger.info("Resolved ToolReference '%s' -> %s", field_name, tool_ref.tool_module_info)
416
412
  except Exception:
417
413
  logger.exception("Failed to resolve ToolReference '%s'", field_name)
418
414
 
419
415
  @classmethod
420
416
  async def _resolve_list_items(
421
- cls, items: list, registry: "RegistryStrategy", communication: "CommunicationStrategy"
417
+ cls,
418
+ items: list,
419
+ registry: "RegistryStrategy",
420
+ communication: "CommunicationStrategy",
421
+ resolved_tools: dict[str, ToolModuleInfo],
422
422
  ) -> None:
423
423
  """Resolve ToolReference instances in a list.
424
424
 
@@ -426,16 +426,32 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
426
426
  items: List of items to process.
427
427
  registry: Registry service for resolution.
428
428
  communication: Communication service for module schemas.
429
+ resolved_tools: Cache of already resolved tools.
429
430
  """
430
431
  for item in items:
431
432
  if isinstance(item, ToolReference):
432
- await cls._resolve_single_tool_reference("list_item", item, registry, communication)
433
+ await cls._resolve_single_tool_reference(
434
+ "list_item",
435
+ item,
436
+ registry,
437
+ communication,
438
+ resolved_tools,
439
+ )
433
440
  elif isinstance(item, BaseModel):
434
- await cls._resolve_tool_references_recursive(item, registry, communication)
441
+ await cls._resolve_tool_references_recursive(
442
+ item,
443
+ registry,
444
+ communication,
445
+ resolved_tools,
446
+ )
435
447
 
436
448
  @classmethod
437
449
  async def _resolve_dict_values(
438
- cls, mapping: dict, registry: "RegistryStrategy", communication: "CommunicationStrategy"
450
+ cls,
451
+ mapping: dict,
452
+ registry: "RegistryStrategy",
453
+ communication: "CommunicationStrategy",
454
+ resolved_tools: dict[str, ToolModuleInfo],
439
455
  ) -> None:
440
456
  """Resolve ToolReference instances in dict values.
441
457
 
@@ -443,63 +459,86 @@ class SetupModel(BaseModel, Generic[SetupModelT]):
443
459
  mapping: Dict to process.
444
460
  registry: Registry service for resolution.
445
461
  communication: Communication service for module schemas.
462
+ resolved_tools: Cache of already resolved tools.
446
463
  """
447
464
  for item in mapping.values():
448
465
  if isinstance(item, ToolReference):
449
- await cls._resolve_single_tool_reference("dict_value", item, registry, communication)
466
+ await cls._resolve_single_tool_reference(
467
+ "dict_value",
468
+ item,
469
+ registry,
470
+ communication,
471
+ resolved_tools,
472
+ )
450
473
  elif isinstance(item, BaseModel):
451
- await cls._resolve_tool_references_recursive(item, registry, communication)
474
+ await cls._resolve_tool_references_recursive(
475
+ item,
476
+ registry,
477
+ communication,
478
+ resolved_tools,
479
+ )
452
480
 
453
481
  def build_tool_cache(self) -> ToolCache:
454
- """Build tool cache from resolved ToolReferences, populating companion fields.
482
+ """Build tool cache from resolved ToolReferences.
455
483
 
456
484
  Returns:
457
485
  ToolCache with field names as keys and ToolModuleInfo as values.
458
486
  """
459
- logger.info("Building tool cache")
460
487
  cache = ToolCache()
461
488
  self._build_tool_cache_recursive(self, cache)
462
489
  logger.info("Tool cache built: %d entries", len(cache.entries))
463
490
  return cache
464
491
 
465
- def _build_tool_cache_recursive(self, model_instance: BaseModel, cache: ToolCache) -> None: # noqa: C901
466
- """Recursively build tool cache and populate companion fields.
492
+ def _build_tool_cache_recursive(self, model_instance: BaseModel, cache: ToolCache) -> None:
493
+ """Recursively build tool cache from ToolReferences.
467
494
 
468
495
  Args:
469
496
  model_instance: Model instance to process.
470
497
  cache: ToolCache to populate.
471
498
  """
472
- for field_name, field_value in model_instance.__dict__.items():
499
+ for field_value in model_instance.__dict__.values():
473
500
  if field_value is None:
474
501
  continue
475
502
  if isinstance(field_value, ToolReference):
476
- cache_field_name = f"{field_name}_cache"
477
-
478
- cached_info = getattr(model_instance, cache_field_name, None)
479
- module_info = field_value.tool_module_info or cached_info
503
+ module_info = self.resolved_tools.get(field_value.slug or "") or field_value.tool_module_info
480
504
  if module_info:
481
- if not cached_info:
482
- setattr(model_instance, cache_field_name, module_info)
505
+ self.resolved_tools[module_info.setup_id] = module_info
483
506
  cache.add(module_info.module_id, module_info)
484
- logger.debug("Added tool to cache: %s", module_info.module_id)
485
507
  elif isinstance(field_value, BaseModel):
486
508
  self._build_tool_cache_recursive(field_value, cache)
487
509
  elif isinstance(field_value, list):
488
- cache_field_name = f"{field_name}_cache"
489
- cached_infos = getattr(model_instance, cache_field_name, None) or []
490
- resolved_infos: list[ToolModuleInfo] = []
491
-
492
- for idx, item in enumerate(field_value):
493
- if isinstance(item, ToolReference):
494
- # Use resolved info or fallback to cached
495
- module_info = item.tool_module_info or (cached_infos[idx] if idx < len(cached_infos) else None)
496
- if module_info:
497
- resolved_infos.append(module_info)
498
- cache.add(module_info.module_id, module_info)
499
- logger.debug("Added tool to cache: %s", module_info.module_id)
500
- elif isinstance(item, BaseModel):
501
- self._build_tool_cache_recursive(item, cache)
502
-
503
- # Update companion field with resolved infos
504
- if resolved_infos:
505
- setattr(model_instance, cache_field_name, resolved_infos)
510
+ self._process_list_items(field_value, cache)
511
+ elif isinstance(field_value, dict):
512
+ self._process_dict_values(field_value, cache)
513
+
514
+ def _process_list_items(self, items: list, cache: ToolCache) -> None:
515
+ """Process list items for ToolReferences.
516
+
517
+ Args:
518
+ items: List to process.
519
+ cache: ToolCache to populate.
520
+ """
521
+ for item in items:
522
+ if isinstance(item, ToolReference):
523
+ module_info = self.resolved_tools.get(item.slug or "") or item.tool_module_info
524
+ if module_info:
525
+ self.resolved_tools[module_info.setup_id] = module_info
526
+ cache.add(module_info.module_id, module_info)
527
+ elif isinstance(item, BaseModel):
528
+ self._build_tool_cache_recursive(item, cache)
529
+
530
+ def _process_dict_values(self, mapping: dict, cache: ToolCache) -> None:
531
+ """Process dict values for ToolReferences.
532
+
533
+ Args:
534
+ mapping: Dict to process.
535
+ cache: ToolCache to populate.
536
+ """
537
+ for item in mapping.values():
538
+ if isinstance(item, ToolReference):
539
+ module_info = self.resolved_tools.get(item.slug or "") or item.tool_module_info
540
+ if module_info:
541
+ self.resolved_tools[module_info.setup_id] = module_info
542
+ cache.add(module_info.module_id, module_info)
543
+ elif isinstance(item, BaseModel):
544
+ self._build_tool_cache_recursive(item, cache)
@@ -52,6 +52,7 @@ class ToolModuleInfo(ModuleInfo):
52
52
  """Module info for tool modules."""
53
53
 
54
54
  tools: list[ToolDefinition]
55
+ setup_id: str
55
56
 
56
57
 
57
58
  class ToolCache(BaseModel):
@@ -59,22 +60,22 @@ class ToolCache(BaseModel):
59
60
 
60
61
  entries: dict[str, ToolModuleInfo] = Field(default_factory=dict)
61
62
 
62
- def add(self, setup_tool_name: str, tool_module_info: ToolModuleInfo) -> None:
63
+ def add(self, setup_id: str, tool_module_info: ToolModuleInfo) -> None:
63
64
  """Add a tool to the cache.
64
65
 
65
66
  Args:
66
- setup_tool_name: Field name from SetupModel used as cache key.
67
+ setup_id: Field name from SetupModel used as cache key.
67
68
  tool_module_info: Resolved tool module information.
68
69
  """
69
- self.entries[setup_tool_name] = tool_module_info
70
+ self.entries[setup_id] = tool_module_info
70
71
  logger.debug(
71
72
  "Tool cached",
72
- extra={"setup_tool_name": setup_tool_name, "module_id": tool_module_info.module_id},
73
+ extra={"setup_id": setup_id, "module_id": tool_module_info.module_id},
73
74
  )
74
75
 
75
76
  async def get(
76
77
  self,
77
- setup_tool_name: str,
78
+ setup_id: str,
78
79
  *,
79
80
  registry: RegistryStrategy | None = None,
80
81
  communication: "CommunicationStrategy | None" = None,
@@ -82,28 +83,28 @@ class ToolCache(BaseModel):
82
83
  """Get a tool from cache, optionally querying registry on miss.
83
84
 
84
85
  Args:
85
- setup_tool_name: Field name to look up.
86
+ setup_id: Field name to look up.
86
87
  registry: Optional registry to query on cache miss.
87
88
  communication: Optional communication strategy for schema fetching.
88
89
 
89
90
  Returns:
90
91
  ToolModuleInfo if found, None otherwise.
91
92
  """
92
- cached = self.entries.get(setup_tool_name)
93
+ cached = self.entries.get(setup_id)
93
94
  if cached:
94
95
  return cached
95
96
 
96
97
  if registry and communication:
97
98
  try:
98
- setup_info = registry.get_setup(setup_tool_name)
99
+ setup_info = registry.get_setup(setup_id)
99
100
  if setup_info and setup_info.module_id:
100
101
  info = registry.discover_by_id(setup_info.module_id)
101
102
  if info:
102
- tool_info = await module_info_to_tool_module_info(info, communication)
103
- self.add(setup_tool_name, tool_info)
103
+ tool_info = await module_info_to_tool_module_info(info, setup_id, communication)
104
+ self.add(setup_id, tool_info)
104
105
  return tool_info
105
106
  except Exception:
106
- logger.exception("Registry lookup failed", extra={"setup_tool_name": setup_tool_name})
107
+ logger.exception("Registry lookup failed", extra={"setup_id": setup_id})
107
108
 
108
109
  return None
109
110
 
@@ -122,6 +123,7 @@ class ToolCache(BaseModel):
122
123
 
123
124
  async def module_info_to_tool_module_info(
124
125
  module_info: ModuleInfo,
126
+ setup_id: str,
125
127
  communication: "CommunicationStrategy",
126
128
  *,
127
129
  llm_format: bool = True,
@@ -133,6 +135,7 @@ async def module_info_to_tool_module_info(
133
135
 
134
136
  Args:
135
137
  module_info: Module info from registry.
138
+ setup_id: Setup ID from tool configuration.
136
139
  communication: Communication strategy for gRPC calls.
137
140
  llm_format: Use LLM-friendly schema format.
138
141
 
@@ -161,6 +164,7 @@ async def module_info_to_tool_module_info(
161
164
  documentation=module_info.documentation,
162
165
  status=module_info.status,
163
166
  tools=tools,
167
+ setup_id=setup_id,
164
168
  )
165
169
 
166
170
 
@@ -115,7 +115,7 @@ class ToolReference(BaseModel):
115
115
  self.config.module_id = setup.module_id
116
116
  info = registry.discover_by_id(self.config.module_id)
117
117
  if info:
118
- tool_module_info = await module_info_to_tool_module_info(info, communication)
118
+ tool_module_info = await module_info_to_tool_module_info(info, self.config.setup_id, communication)
119
119
  self._cached_info = tool_module_info
120
120
  return tool_module_info
121
121
 
@@ -126,7 +126,9 @@ class ToolReference(BaseModel):
126
126
  organization_id=self.config.organization_id,
127
127
  )
128
128
  if results:
129
- tool_module_info = await module_info_to_tool_module_info(results[0], communication)
129
+ tool_module_info = await module_info_to_tool_module_info(
130
+ results[0], self.config.setup_id, communication
131
+ )
130
132
  self._cached_info = tool_module_info
131
133
  self.config.module_id = tool_module_info.module_id
132
134
  return tool_module_info
@@ -556,21 +556,7 @@ class BaseModule( # noqa: PLR0904
556
556
  await self._resolve_tools(config_setup_data)
557
557
  updated_config = await self.run_config_setup(self.context, config_setup_data)
558
558
 
559
- # Build wrapper: original structure with updated content
560
- wrapper = config_setup_data.model_dump()
561
- wrapper["content"] = updated_config.model_dump()
562
-
563
- # Debug logging
564
- content = wrapper.get("content", {})
565
- logger.info(
566
- "Config setup wrapper: keys=%s, content_keys=%s, tools_cache=%s",
567
- list(wrapper.keys()),
568
- list(content.keys()) if isinstance(content, dict) else "N/A",
569
- content.get("tools_cache") if isinstance(content, dict) else "N/A",
570
- extra=self.context.session.current_ids(),
571
- )
572
-
573
- setup_model = await self.create_setup_model(wrapper)
559
+ setup_model = await self.create_setup_model(updated_config.model_dump())
574
560
  await callback(setup_model)
575
561
  self._status = ModuleStatus.STOPPING
576
562
  except Exception: