digitalkin 0.3.2.dev7__tar.gz → 0.3.2.dev10__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 (153) hide show
  1. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/PKG-INFO +1 -1
  2. digitalkin-0.3.2.dev10/examples/modules/archetype_with_tools_module.py +244 -0
  3. digitalkin-0.3.2.dev10/examples/monitoring/digitalkin_observability/__init__.py +46 -0
  4. digitalkin-0.3.2.dev10/examples/monitoring/digitalkin_observability/http_server.py +150 -0
  5. digitalkin-0.3.2.dev10/examples/monitoring/digitalkin_observability/interceptors.py +176 -0
  6. digitalkin-0.3.2.dev10/examples/monitoring/digitalkin_observability/metrics.py +201 -0
  7. digitalkin-0.3.2.dev10/examples/monitoring/digitalkin_observability/prometheus.py +137 -0
  8. digitalkin-0.3.2.dev10/examples/monitoring/tests/test_metrics.py +172 -0
  9. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/pyproject.toml +2 -2
  10. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/__version__.py +1 -1
  11. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/module_servicer.py +0 -11
  12. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/utils/grpc_client_wrapper.py +2 -2
  13. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/utils/utility_schema_extender.py +2 -1
  14. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/grpc_servers/models.py +91 -6
  15. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/module_context.py +136 -23
  16. digitalkin-0.3.2.dev10/src/digitalkin/models/module/setup_types.py +490 -0
  17. digitalkin-0.3.2.dev10/src/digitalkin/models/module/tool_cache.py +68 -0
  18. digitalkin-0.3.2.dev10/src/digitalkin/models/module/tool_reference.py +117 -0
  19. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/services/registry.py +0 -7
  20. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/_base_module.py +85 -58
  21. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/registry/__init__.py +1 -1
  22. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/registry/default_registry.py +1 -1
  23. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/registry/grpc_registry.py +1 -1
  24. digitalkin-0.3.2.dev10/src/digitalkin/services/registry/registry_models.py +15 -0
  25. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/registry/registry_strategy.py +1 -1
  26. digitalkin-0.3.2.dev10/src/digitalkin/utils/schema_splitter.py +207 -0
  27. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin.egg-info/PKG-INFO +1 -1
  28. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin.egg-info/SOURCES.txt +9 -2
  29. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin.egg-info/top_level.txt +1 -0
  30. digitalkin-0.3.2.dev7/src/digitalkin/models/module/module_helpers.py +0 -189
  31. digitalkin-0.3.2.dev7/src/digitalkin/models/module/setup_types.py +0 -573
  32. digitalkin-0.3.2.dev7/src/digitalkin/models/module/tool_cache.py +0 -228
  33. digitalkin-0.3.2.dev7/src/digitalkin/models/module/tool_reference.py +0 -120
  34. digitalkin-0.3.2.dev7/src/digitalkin/services/registry/registry_models.py +0 -43
  35. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/LICENSE +0 -0
  36. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/README.md +0 -0
  37. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/__init__.py +0 -0
  38. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/mock/__init__.py +0 -0
  39. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/mock/mock_pb2.py +0 -0
  40. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/mock/mock_pb2_grpc.py +0 -0
  41. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/server_async_insecure.py +0 -0
  42. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/server_async_secure.py +0 -0
  43. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/server_sync_insecure.py +0 -0
  44. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/base_server/server_sync_secure.py +0 -0
  45. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/modules/__init__.py +0 -0
  46. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/modules/cpu_intensive_module.py +0 -0
  47. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/modules/dynamic_setup_module.py +0 -0
  48. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/modules/minimal_llm_module.py +0 -0
  49. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/modules/text_transform_module.py +0 -0
  50. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/services/filesystem_module.py +0 -0
  51. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/examples/services/storage_module.py +0 -0
  52. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/setup.cfg +0 -0
  53. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/__init__.py +0 -0
  54. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/__init__.py +0 -0
  55. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/common/__init__.py +0 -0
  56. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/common/factories.py +0 -0
  57. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/job_manager/__init__.py +0 -0
  58. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/job_manager/base_job_manager.py +0 -0
  59. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/job_manager/single_job_manager.py +0 -0
  60. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/job_manager/taskiq_broker.py +0 -0
  61. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/job_manager/taskiq_job_manager.py +0 -0
  62. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/__init__.py +0 -0
  63. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/base_task_manager.py +0 -0
  64. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/local_task_manager.py +0 -0
  65. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/remote_task_manager.py +0 -0
  66. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/surrealdb_repository.py +0 -0
  67. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/task_executor.py +0 -0
  68. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/core/task_manager/task_session.py +0 -0
  69. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/__init__.py +0 -0
  70. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/_base_server.py +0 -0
  71. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/module_server.py +0 -0
  72. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/utils/__init__.py +0 -0
  73. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/utils/exceptions.py +0 -0
  74. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/grpc_servers/utils/grpc_error_handler.py +0 -0
  75. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/logger.py +0 -0
  76. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/__init__.py +0 -0
  77. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/base_mixin.py +0 -0
  78. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/callback_mixin.py +0 -0
  79. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/chat_history_mixin.py +0 -0
  80. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/cost_mixin.py +0 -0
  81. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/file_history_mixin.py +0 -0
  82. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/filesystem_mixin.py +0 -0
  83. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/logger_mixin.py +0 -0
  84. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/mixins/storage_mixin.py +0 -0
  85. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/__init__.py +0 -0
  86. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/core/__init__.py +0 -0
  87. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/core/job_manager_models.py +0 -0
  88. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/core/task_monitor.py +0 -0
  89. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/grpc_servers/__init__.py +0 -0
  90. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/grpc_servers/types.py +0 -0
  91. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/__init__.py +0 -0
  92. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/base_types.py +0 -0
  93. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/module.py +0 -0
  94. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/module_types.py +0 -0
  95. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/module/utility.py +0 -0
  96. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/services/__init__.py +0 -0
  97. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/services/cost.py +0 -0
  98. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/models/services/storage.py +0 -0
  99. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/__init__.py +0 -0
  100. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/archetype_module.py +0 -0
  101. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/tool_module.py +0 -0
  102. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/trigger_handler.py +0 -0
  103. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/triggers/__init__.py +0 -0
  104. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/triggers/healthcheck_ping_trigger.py +0 -0
  105. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/triggers/healthcheck_services_trigger.py +0 -0
  106. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/modules/triggers/healthcheck_status_trigger.py +0 -0
  107. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/py.typed +0 -0
  108. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/__init__.py +0 -0
  109. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/agent/__init__.py +0 -0
  110. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/agent/agent_strategy.py +0 -0
  111. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/agent/default_agent.py +0 -0
  112. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/base_strategy.py +0 -0
  113. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/communication/__init__.py +0 -0
  114. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/communication/communication_strategy.py +0 -0
  115. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/communication/default_communication.py +0 -0
  116. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/communication/grpc_communication.py +0 -0
  117. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/cost/__init__.py +0 -0
  118. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/cost/cost_strategy.py +0 -0
  119. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/cost/default_cost.py +0 -0
  120. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/cost/grpc_cost.py +0 -0
  121. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/filesystem/__init__.py +0 -0
  122. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/filesystem/default_filesystem.py +0 -0
  123. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/filesystem/filesystem_strategy.py +0 -0
  124. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/filesystem/grpc_filesystem.py +0 -0
  125. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/identity/__init__.py +0 -0
  126. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/identity/default_identity.py +0 -0
  127. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/identity/identity_strategy.py +0 -0
  128. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/registry/exceptions.py +0 -0
  129. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/services_config.py +0 -0
  130. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/services_models.py +0 -0
  131. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/setup/__init__.py +0 -0
  132. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/setup/default_setup.py +0 -0
  133. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/setup/grpc_setup.py +0 -0
  134. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/setup/setup_strategy.py +0 -0
  135. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/snapshot/__init__.py +0 -0
  136. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/snapshot/default_snapshot.py +0 -0
  137. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/snapshot/snapshot_strategy.py +0 -0
  138. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/storage/__init__.py +0 -0
  139. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/storage/default_storage.py +0 -0
  140. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/storage/grpc_storage.py +0 -0
  141. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/storage/storage_strategy.py +0 -0
  142. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/user_profile/__init__.py +0 -0
  143. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/user_profile/default_user_profile.py +0 -0
  144. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/user_profile/grpc_user_profile.py +0 -0
  145. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/services/user_profile/user_profile_strategy.py +0 -0
  146. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/__init__.py +0 -0
  147. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/arg_parser.py +0 -0
  148. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/development_mode_action.py +0 -0
  149. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/dynamic_schema.py +0 -0
  150. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/llm_ready_schema.py +0 -0
  151. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin/utils/package_discover.py +0 -0
  152. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin.egg-info/dependency_links.txt +0 -0
  153. {digitalkin-0.3.2.dev7 → digitalkin-0.3.2.dev10}/src/digitalkin.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.3.2.dev7
3
+ Version: 0.3.2.dev10
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
@@ -0,0 +1,244 @@
1
+ """Example archetype module with tool cache integration."""
2
+
3
+ import logging
4
+ from typing import Any, ClassVar, Literal
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from digitalkin.models.grpc_servers.models import ClientConfig, SecurityMode, ServerMode
9
+ from digitalkin.models.module.module_context import ModuleContext
10
+ from digitalkin.models.module.setup_types import SetupModel
11
+ from digitalkin.models.module.tool_reference import (
12
+ ToolReference,
13
+ ToolReferenceConfig,
14
+ ToolSelectionMode,
15
+ )
16
+ from digitalkin.modules._base_module import BaseModule # noqa: PLC2701
17
+ from digitalkin.services.services_models import ServicesStrategy
18
+
19
+ logging.basicConfig(
20
+ level=logging.DEBUG,
21
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
22
+ )
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class MessageInputPayload(BaseModel):
27
+ """Message input payload."""
28
+
29
+ payload_type: Literal["message"] = "message"
30
+ user_prompt: str
31
+
32
+
33
+ class ArchetypeInput(BaseModel):
34
+ """Archetype input."""
35
+
36
+ payload: MessageInputPayload = Field(discriminator="payload_type")
37
+
38
+
39
+ class MessageOutputPayload(BaseModel):
40
+ """Message output payload."""
41
+
42
+ payload_type: Literal["message"] = "message"
43
+ response: str
44
+ tools_used: list[str] = Field(default_factory=list)
45
+
46
+
47
+ class ArchetypeOutput(BaseModel):
48
+ """Archetype output."""
49
+
50
+ payload: MessageOutputPayload = Field(discriminator="payload_type")
51
+
52
+
53
+ class ArchetypeSetup(SetupModel):
54
+ """Setup with tool references resolved during config setup."""
55
+
56
+ model_name: str = Field(
57
+ default="gpt-4",
58
+ json_schema_extra={"config": True},
59
+ )
60
+ temperature: float = Field(
61
+ default=0.7,
62
+ json_schema_extra={"config": True},
63
+ )
64
+
65
+ search_tool: ToolReference = Field(
66
+ default_factory=lambda: ToolReference(
67
+ config=ToolReferenceConfig(
68
+ mode=ToolSelectionMode.FIXED,
69
+ module_id="search-tool-v1",
70
+ )
71
+ ),
72
+ json_schema_extra={"config": True},
73
+ )
74
+
75
+ calculator_tool: ToolReference = Field(
76
+ default_factory=lambda: ToolReference(
77
+ config=ToolReferenceConfig(
78
+ mode=ToolSelectionMode.TAG,
79
+ tag="math-calculator",
80
+ )
81
+ ),
82
+ json_schema_extra={"config": True},
83
+ )
84
+
85
+ dynamic_tool: ToolReference = Field(
86
+ default_factory=lambda: ToolReference(
87
+ config=ToolReferenceConfig(
88
+ mode=ToolSelectionMode.DISCOVERABLE,
89
+ )
90
+ ),
91
+ json_schema_extra={"config": True},
92
+ )
93
+
94
+ system_prompt: str = Field(
95
+ default="You are a helpful assistant with access to tools.",
96
+ json_schema_extra={"hidden": True},
97
+ )
98
+
99
+
100
+ class ArchetypeConfigSetup(BaseModel):
101
+ """Config setup model."""
102
+
103
+ additional_instructions: str | None = None
104
+
105
+
106
+ class ArchetypeSecret(BaseModel):
107
+ """Secrets model."""
108
+
109
+
110
+ client_config = ClientConfig(
111
+ host="[::]",
112
+ port=50152,
113
+ mode=ServerMode.ASYNC,
114
+ security=SecurityMode.INSECURE,
115
+ credentials=None,
116
+ )
117
+
118
+
119
+ class ArchetypeWithToolsModule(
120
+ BaseModule[
121
+ ArchetypeInput,
122
+ ArchetypeOutput,
123
+ ArchetypeSetup,
124
+ ArchetypeSecret,
125
+ ]
126
+ ):
127
+ """Archetype module demonstrating tool cache usage."""
128
+
129
+ name = "ArchetypeWithToolsModule"
130
+ description = "Archetype with tool cache integration"
131
+
132
+ config_setup_format = ArchetypeConfigSetup
133
+ input_format = ArchetypeInput
134
+ output_format = ArchetypeOutput
135
+ setup_format = ArchetypeSetup
136
+ secret_format = ArchetypeSecret
137
+
138
+ metadata: ClassVar[dict[str, Any]] = {
139
+ "name": "ArchetypeWithToolsModule",
140
+ "version": "1.0.0",
141
+ "tags": ["archetype", "tools"],
142
+ }
143
+
144
+ services_config_strategies: ClassVar[dict[str, ServicesStrategy | None]] = {}
145
+ services_config_params: ClassVar[dict[str, dict[str, Any | None] | None]] = {
146
+ "registry": {
147
+ "config": {},
148
+ "client_config": client_config,
149
+ },
150
+ }
151
+
152
+ async def run_config_setup(
153
+ self,
154
+ context: ModuleContext, # noqa: ARG002
155
+ config_setup_data: ArchetypeSetup,
156
+ ) -> ArchetypeSetup:
157
+ """Custom config setup logic, runs in parallel with tool resolution.
158
+
159
+ Args:
160
+ context: Module context with services.
161
+ config_setup_data: Setup data being configured.
162
+
163
+ Returns:
164
+ Configured setup data.
165
+ """
166
+ logger.info("Running config setup for %s", self.name)
167
+ return config_setup_data
168
+
169
+ async def initialize(self, context: ModuleContext, setup_data: ArchetypeSetup) -> None: # noqa: ARG002
170
+ """Initialize module.
171
+
172
+ Args:
173
+ context: Module context with services and tool cache.
174
+ setup_data: Setup data for the module.
175
+ """
176
+ logger.info("Initializing %s", self.name)
177
+ if context.tool_cache:
178
+ logger.info("Available tools: %s", context.tool_cache.list_tools())
179
+
180
+ async def run(
181
+ self,
182
+ input_data: ArchetypeInput,
183
+ setup_data: ArchetypeSetup, # noqa: ARG002
184
+ ) -> None:
185
+ """Run module with tool cache lookups and call_module_by_id.
186
+
187
+ Args:
188
+ input_data: Input data to process.
189
+ setup_data: Setup configuration.
190
+ """
191
+ logger.info("Running %s", self.name)
192
+
193
+ tools_used: list[str] = []
194
+ tool_results: list[str] = []
195
+
196
+ # Get search tool from cache and call via call_module_by_id
197
+ search_info = self.context.tool_cache.get("search_tool")
198
+ if search_info:
199
+ tools_used.append(f"search:{search_info.module_id}")
200
+ async for response in self.context.call_module_by_id(
201
+ module_id=search_info.module_id,
202
+ input_data={"query": input_data.payload.user_prompt},
203
+ setup_id=self.context.session.setup_id,
204
+ mission_id=self.context.session.mission_id,
205
+ ):
206
+ tool_results.append(f"search_result: {response}")
207
+
208
+ # Get calculator tool from cache
209
+ calc_info = self.context.tool_cache.get("calculator_tool")
210
+ if calc_info:
211
+ tools_used.append(f"calculator:{calc_info.module_id}")
212
+ async for response in self.context.call_module_by_id(
213
+ module_id=calc_info.module_id,
214
+ input_data={"expression": "2 + 2"},
215
+ setup_id=self.context.session.setup_id,
216
+ mission_id=self.context.session.mission_id,
217
+ ):
218
+ tool_results.append(f"calc_result: {response}")
219
+
220
+ # Dynamic discovery via registry fallback for tools not in cache
221
+ dynamic_info = self.context.tool_cache.get(
222
+ "some_dynamic_tool",
223
+ registry=self.context.registry,
224
+ )
225
+ if dynamic_info:
226
+ tools_used.append(f"dynamic:{dynamic_info.module_id}")
227
+ async for response in self.context.call_module_by_id(
228
+ module_id=dynamic_info.module_id,
229
+ input_data={"prompt": input_data.payload.user_prompt},
230
+ setup_id=self.context.session.setup_id,
231
+ mission_id=self.context.session.mission_id,
232
+ ):
233
+ tool_results.append(f"dynamic_result: {response}")
234
+
235
+ response = MessageOutputPayload(
236
+ response=f"Processed: {input_data.payload.user_prompt} | Results: {len(tool_results)}",
237
+ tools_used=tools_used,
238
+ )
239
+
240
+ await self.context.callbacks.send_message(ArchetypeOutput(payload=response))
241
+
242
+ async def cleanup(self) -> None:
243
+ """Clean up resources."""
244
+ logger.info("Cleaning up %s", self.name)
@@ -0,0 +1,46 @@
1
+ """Standalone observability module for DigitalKin.
2
+
3
+ This module can be copied into your project and used independently.
4
+ It has no dependencies on the digitalkin package.
5
+
6
+ Usage:
7
+ from digitalkin_observability import (
8
+ MetricsCollector,
9
+ MetricsServer,
10
+ MetricsServerInterceptor,
11
+ PrometheusExporter,
12
+ get_metrics,
13
+ start_metrics_server,
14
+ stop_metrics_server,
15
+ )
16
+
17
+ # Start metrics HTTP server
18
+ start_metrics_server(port=8081)
19
+
20
+ # Track metrics
21
+ metrics = get_metrics()
22
+ metrics.inc_jobs_started("my_module")
23
+ metrics.inc_jobs_completed("my_module", duration=1.5)
24
+
25
+ # Export to Prometheus format
26
+ print(PrometheusExporter.export())
27
+ """
28
+
29
+ from digitalkin_observability.http_server import (
30
+ MetricsServer,
31
+ start_metrics_server,
32
+ stop_metrics_server,
33
+ )
34
+ from digitalkin_observability.interceptors import MetricsServerInterceptor
35
+ from digitalkin_observability.metrics import MetricsCollector, get_metrics
36
+ from digitalkin_observability.prometheus import PrometheusExporter
37
+
38
+ __all__ = [
39
+ "MetricsCollector",
40
+ "MetricsServer",
41
+ "MetricsServerInterceptor",
42
+ "PrometheusExporter",
43
+ "get_metrics",
44
+ "start_metrics_server",
45
+ "stop_metrics_server",
46
+ ]
@@ -0,0 +1,150 @@
1
+ """Simple HTTP server for exposing Prometheus metrics.
2
+
3
+ This module provides an HTTP server that exposes metrics at /metrics endpoint.
4
+ No external dependencies required beyond Python standard library.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from http.server import BaseHTTPRequestHandler, HTTPServer
11
+ from threading import Thread
12
+ from typing import TYPE_CHECKING, ClassVar
13
+
14
+ if TYPE_CHECKING:
15
+ from typing import Self
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class MetricsHandler(BaseHTTPRequestHandler):
21
+ """HTTP request handler for metrics endpoint."""
22
+
23
+ def do_GET(self) -> None:
24
+ """Handle GET requests."""
25
+ if self.path == "/metrics":
26
+ self._serve_metrics()
27
+ elif self.path == "/health":
28
+ self._serve_health()
29
+ else:
30
+ self.send_error(404, "Not Found")
31
+
32
+ def _serve_metrics(self) -> None:
33
+ """Serve Prometheus metrics."""
34
+ from digitalkin_observability.prometheus import PrometheusExporter
35
+
36
+ content = PrometheusExporter.export()
37
+ self.send_response(200)
38
+ self.send_header("Content-Type", "text/plain; charset=utf-8")
39
+ self.send_header("Content-Length", str(len(content)))
40
+ self.end_headers()
41
+ self.wfile.write(content.encode("utf-8"))
42
+
43
+ def _serve_health(self) -> None:
44
+ """Serve health check."""
45
+ content = '{"status": "ok"}'
46
+ self.send_response(200)
47
+ self.send_header("Content-Type", "application/json")
48
+ self.send_header("Content-Length", str(len(content)))
49
+ self.end_headers()
50
+ self.wfile.write(content.encode("utf-8"))
51
+
52
+ def log_message(self, format: str, *args: object) -> None:
53
+ """Suppress default logging."""
54
+
55
+
56
+ class MetricsServer:
57
+ """HTTP server for exposing metrics to Prometheus.
58
+
59
+ Usage:
60
+ server = MetricsServer(port=8081)
61
+ server.start()
62
+ # ... run your application ...
63
+ server.stop()
64
+
65
+ Or as context manager:
66
+ with MetricsServer(port=8081):
67
+ # ... run your application ...
68
+
69
+ Or as async context manager:
70
+ async with MetricsServer(port=8081):
71
+ # ... run your application ...
72
+ """
73
+
74
+ instance: ClassVar["MetricsServer | None"] = None
75
+
76
+ def __init__(self, host: str = "0.0.0.0", port: int = 8081) -> None:
77
+ """Initialize the metrics server.
78
+
79
+ Args:
80
+ host: Host to bind to (default: 0.0.0.0 for all interfaces).
81
+ port: Port to listen on (default: 8081).
82
+ """
83
+ self.host = host
84
+ self.port = port
85
+ self._server: HTTPServer | None = None
86
+ self._thread: Thread | None = None
87
+
88
+ def start(self) -> None:
89
+ """Start the metrics server in a background thread."""
90
+ if self._server is not None:
91
+ logger.warning("Metrics server already running")
92
+ return
93
+
94
+ self._server = HTTPServer((self.host, self.port), MetricsHandler)
95
+ self._thread = Thread(target=self._server.serve_forever, daemon=True)
96
+ self._thread.start()
97
+ logger.info(
98
+ "Metrics server started on http://%s:%s/metrics",
99
+ self.host,
100
+ self.port,
101
+ )
102
+
103
+ def stop(self) -> None:
104
+ """Stop the metrics server."""
105
+ if self._server is not None:
106
+ self._server.shutdown()
107
+ self._server = None
108
+ self._thread = None
109
+ logger.info("Metrics server stopped")
110
+
111
+ async def __aenter__(self) -> "Self":
112
+ """Async context manager entry."""
113
+ self.start()
114
+ return self
115
+
116
+ async def __aexit__(self, *args: object) -> None:
117
+ """Async context manager exit."""
118
+ self.stop()
119
+
120
+ def __enter__(self) -> "Self":
121
+ """Context manager entry."""
122
+ self.start()
123
+ return self
124
+
125
+ def __exit__(self, *args: object) -> None:
126
+ """Context manager exit."""
127
+ self.stop()
128
+
129
+
130
+ def start_metrics_server(host: str = "0.0.0.0", port: int = 8081) -> MetricsServer:
131
+ """Start a metrics server singleton.
132
+
133
+ Args:
134
+ host: Host to bind to.
135
+ port: Port to listen on.
136
+
137
+ Returns:
138
+ The MetricsServer instance.
139
+ """
140
+ if MetricsServer.instance is None:
141
+ MetricsServer.instance = MetricsServer(host, port)
142
+ MetricsServer.instance.start()
143
+ return MetricsServer.instance
144
+
145
+
146
+ def stop_metrics_server() -> None:
147
+ """Stop the metrics server singleton."""
148
+ if MetricsServer.instance is not None:
149
+ MetricsServer.instance.stop()
150
+ MetricsServer.instance = None
@@ -0,0 +1,176 @@
1
+ """gRPC interceptors for automatic metrics collection.
2
+
3
+ This module provides gRPC server interceptors that automatically track
4
+ request duration and errors. Requires grpcio package.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import time
10
+ from typing import TYPE_CHECKING
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Awaitable, Callable
14
+ from typing import Any
15
+
16
+ import grpc
17
+
18
+ from digitalkin_observability.metrics import get_metrics
19
+
20
+
21
+ class MetricsServerInterceptor:
22
+ """Intercepts all gRPC calls to collect metrics.
23
+
24
+ This interceptor automatically tracks:
25
+ - Request duration (histogram)
26
+ - Error counts
27
+
28
+ Usage:
29
+ import grpc
30
+ from digitalkin_observability import MetricsServerInterceptor
31
+
32
+ interceptors = [MetricsServerInterceptor()]
33
+ server = grpc.aio.server(interceptors=interceptors)
34
+ """
35
+
36
+ async def intercept_service(
37
+ self,
38
+ continuation: Callable[["grpc.HandlerCallDetails"], Awaitable["grpc.RpcMethodHandler"]],
39
+ handler_call_details: "grpc.HandlerCallDetails",
40
+ ) -> "grpc.RpcMethodHandler":
41
+ """Intercept a gRPC service call to collect metrics.
42
+
43
+ Args:
44
+ continuation: The next interceptor or the actual handler.
45
+ handler_call_details: Details about the call being intercepted.
46
+
47
+ Returns:
48
+ The RPC method handler.
49
+ """
50
+ start = time.perf_counter()
51
+ metrics = get_metrics()
52
+
53
+ try:
54
+ handler = await continuation(handler_call_details)
55
+ return _MetricsWrappedHandler(handler, start, handler_call_details.method)
56
+ except Exception:
57
+ metrics.inc_errors()
58
+ metrics.observe_grpc_duration(time.perf_counter() - start)
59
+ raise
60
+
61
+
62
+ class _MetricsWrappedHandler:
63
+ """Wrapper that measures actual handler execution time."""
64
+
65
+ def __init__(
66
+ self,
67
+ handler: "grpc.RpcMethodHandler",
68
+ start_time: float,
69
+ method: str,
70
+ ) -> None:
71
+ self._handler = handler
72
+ self._start_time = start_time
73
+ self._method = method
74
+
75
+ # Copy attributes from original handler
76
+ self.request_streaming = handler.request_streaming
77
+ self.response_streaming = handler.response_streaming
78
+ self.request_deserializer = handler.request_deserializer
79
+ self.response_serializer = handler.response_serializer
80
+
81
+ # Wrap the appropriate method based on streaming type
82
+ if handler.unary_unary:
83
+ self.unary_unary = self._wrap_unary_unary(handler.unary_unary)
84
+ self.unary_stream = None
85
+ self.stream_unary = None
86
+ self.stream_stream = None
87
+ elif handler.unary_stream:
88
+ self.unary_unary = None
89
+ self.unary_stream = self._wrap_unary_stream(handler.unary_stream)
90
+ self.stream_unary = None
91
+ self.stream_stream = None
92
+ elif handler.stream_unary:
93
+ self.unary_unary = None
94
+ self.unary_stream = None
95
+ self.stream_unary = self._wrap_stream_unary(handler.stream_unary)
96
+ self.stream_stream = None
97
+ elif handler.stream_stream:
98
+ self.unary_unary = None
99
+ self.unary_stream = None
100
+ self.stream_unary = None
101
+ self.stream_stream = self._wrap_stream_stream(handler.stream_stream)
102
+ else:
103
+ self.unary_unary = None
104
+ self.unary_stream = None
105
+ self.stream_unary = None
106
+ self.stream_stream = None
107
+
108
+ def _wrap_unary_unary(
109
+ self,
110
+ handler: Callable[["Any", "grpc.aio.ServicerContext"], Awaitable["Any"]],
111
+ ) -> Callable[["Any", "grpc.aio.ServicerContext"], Awaitable["Any"]]:
112
+ """Wrap a unary-unary handler."""
113
+ async def wrapped(request: "Any", context: "grpc.aio.ServicerContext") -> "Any":
114
+ metrics = get_metrics()
115
+ try:
116
+ return await handler(request, context)
117
+ except Exception:
118
+ metrics.inc_errors()
119
+ raise
120
+ finally:
121
+ metrics.observe_grpc_duration(time.perf_counter() - self._start_time)
122
+
123
+ return wrapped
124
+
125
+ def _wrap_unary_stream(
126
+ self,
127
+ handler: Callable[["Any", "grpc.aio.ServicerContext"], "Any"],
128
+ ) -> Callable[["Any", "grpc.aio.ServicerContext"], "Any"]:
129
+ """Wrap a unary-stream handler."""
130
+ async def wrapped(request: "Any", context: "grpc.aio.ServicerContext") -> "Any":
131
+ metrics = get_metrics()
132
+ try:
133
+ async for response in handler(request, context):
134
+ yield response
135
+ except Exception:
136
+ metrics.inc_errors()
137
+ raise
138
+ finally:
139
+ metrics.observe_grpc_duration(time.perf_counter() - self._start_time)
140
+
141
+ return wrapped
142
+
143
+ def _wrap_stream_unary(
144
+ self,
145
+ handler: Callable[["Any", "grpc.aio.ServicerContext"], Awaitable["Any"]],
146
+ ) -> Callable[["Any", "grpc.aio.ServicerContext"], Awaitable["Any"]]:
147
+ """Wrap a stream-unary handler."""
148
+ async def wrapped(request_iterator: "Any", context: "grpc.aio.ServicerContext") -> "Any":
149
+ metrics = get_metrics()
150
+ try:
151
+ return await handler(request_iterator, context)
152
+ except Exception:
153
+ metrics.inc_errors()
154
+ raise
155
+ finally:
156
+ metrics.observe_grpc_duration(time.perf_counter() - self._start_time)
157
+
158
+ return wrapped
159
+
160
+ def _wrap_stream_stream(
161
+ self,
162
+ handler: Callable[["Any", "grpc.aio.ServicerContext"], "Any"],
163
+ ) -> Callable[["Any", "grpc.aio.ServicerContext"], "Any"]:
164
+ """Wrap a stream-stream handler."""
165
+ async def wrapped(request_iterator: "Any", context: "grpc.aio.ServicerContext") -> "Any":
166
+ metrics = get_metrics()
167
+ try:
168
+ async for response in handler(request_iterator, context):
169
+ yield response
170
+ except Exception:
171
+ metrics.inc_errors()
172
+ raise
173
+ finally:
174
+ metrics.observe_grpc_duration(time.perf_counter() - self._start_time)
175
+
176
+ return wrapped