gatewaysdk 0.3.2__py3-none-any.whl

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 (376) hide show
  1. gatewaysdk/__init__.py +540 -0
  2. gatewaysdk/adapter/__init__.py +15 -0
  3. gatewaysdk/adapter/base.py +94 -0
  4. gatewaysdk/adapter/messages.py +270 -0
  5. gatewaysdk/adapter/triplet.py +1026 -0
  6. gatewaysdk/algorithm/__init__.py +39 -0
  7. gatewaysdk/algorithm/apo/__init__.py +5 -0
  8. gatewaysdk/algorithm/apo/apo.py +898 -0
  9. gatewaysdk/algorithm/apo/prompts/apply_edit_variant01.poml +22 -0
  10. gatewaysdk/algorithm/apo/prompts/apply_edit_variant02.poml +18 -0
  11. gatewaysdk/algorithm/apo/prompts/text_gradient_variant01.poml +18 -0
  12. gatewaysdk/algorithm/apo/prompts/text_gradient_variant02.poml +16 -0
  13. gatewaysdk/algorithm/apo/prompts/text_gradient_variant03.poml +107 -0
  14. gatewaysdk/algorithm/base.py +262 -0
  15. gatewaysdk/algorithm/decorator.py +264 -0
  16. gatewaysdk/algorithm/evals/__init__.py +7 -0
  17. gatewaysdk/algorithm/evals/evals.py +217 -0
  18. gatewaysdk/algorithm/fast.py +250 -0
  19. gatewaysdk/algorithm/gepa/__init__.py +61 -0
  20. gatewaysdk/algorithm/gepa/adapter.py +495 -0
  21. gatewaysdk/algorithm/gepa/gepa.py +570 -0
  22. gatewaysdk/algorithm/gepa/lib/__init__.py +18 -0
  23. gatewaysdk/algorithm/gepa/lib/adapters/README.md +12 -0
  24. gatewaysdk/algorithm/gepa/lib/adapters/__init__.py +0 -0
  25. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/README.md +341 -0
  26. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/__init__.py +1 -0
  27. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/anymaths_adapter.py +174 -0
  28. gatewaysdk/algorithm/gepa/lib/adapters/anymaths_adapter/requirements.txt +1 -0
  29. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/README.md +0 -0
  30. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/__init__.py +0 -0
  31. gatewaysdk/algorithm/gepa/lib/adapters/default_adapter/default_adapter.py +209 -0
  32. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/README.md +7 -0
  33. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/__init__.py +0 -0
  34. gatewaysdk/algorithm/gepa/lib/adapters/dspy_adapter/dspy_adapter.py +307 -0
  35. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/README.md +99 -0
  36. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/dspy_program_proposal_signature.py +137 -0
  37. gatewaysdk/algorithm/gepa/lib/adapters/dspy_full_program_adapter/full_program_adapter.py +268 -0
  38. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/GEPA_RAG.md +621 -0
  39. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/__init__.py +56 -0
  40. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/evaluation_metrics.py +226 -0
  41. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/generic_rag_adapter.py +496 -0
  42. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/rag_pipeline.py +238 -0
  43. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_store_interface.py +212 -0
  44. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/__init__.py +2 -0
  45. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/chroma_store.py +196 -0
  46. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/lancedb_store.py +422 -0
  47. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/milvus_store.py +409 -0
  48. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/qdrant_store.py +368 -0
  49. gatewaysdk/algorithm/gepa/lib/adapters/generic_rag_adapter/vector_stores/weaviate_store.py +418 -0
  50. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/README.md +552 -0
  51. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/__init__.py +37 -0
  52. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_adapter.py +699 -0
  53. gatewaysdk/algorithm/gepa/lib/adapters/mcp_adapter/mcp_client.py +364 -0
  54. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/README.md +9 -0
  55. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/__init__.py +0 -0
  56. gatewaysdk/algorithm/gepa/lib/adapters/terminal_bench_adapter/terminal_bench_adapter.py +217 -0
  57. gatewaysdk/algorithm/gepa/lib/api.py +382 -0
  58. gatewaysdk/algorithm/gepa/lib/core/__init__.py +0 -0
  59. gatewaysdk/algorithm/gepa/lib/core/adapter.py +180 -0
  60. gatewaysdk/algorithm/gepa/lib/core/data_loader.py +74 -0
  61. gatewaysdk/algorithm/gepa/lib/core/engine.py +379 -0
  62. gatewaysdk/algorithm/gepa/lib/core/result.py +233 -0
  63. gatewaysdk/algorithm/gepa/lib/core/state.py +636 -0
  64. gatewaysdk/algorithm/gepa/lib/examples/__init__.py +0 -0
  65. gatewaysdk/algorithm/gepa/lib/examples/aime.py +24 -0
  66. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/eval_default.py +111 -0
  67. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/instruction_prompt.txt +9 -0
  68. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/prompt-templates/optimal_prompt.txt +24 -0
  69. gatewaysdk/algorithm/gepa/lib/examples/anymaths-bench/train_anymaths.py +177 -0
  70. gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/arc_agi.ipynb +25705 -0
  71. gatewaysdk/algorithm/gepa/lib/examples/dspy_full_program_evolution/example.ipynb +348 -0
  72. gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/__init__.py +4 -0
  73. gatewaysdk/algorithm/gepa/lib/examples/mcp_adapter/mcp_optimization_example.py +456 -0
  74. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/RAG_GUIDE.md +613 -0
  75. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/__init__.py +9 -0
  76. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/rag_optimization.py +820 -0
  77. gatewaysdk/algorithm/gepa/lib/examples/rag_adapter/requirements-rag.txt +29 -0
  78. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/instruction_prompt.txt +16 -0
  79. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/prompt-templates/terminus.txt +9 -0
  80. gatewaysdk/algorithm/gepa/lib/examples/terminal-bench/train_terminus.py +161 -0
  81. gatewaysdk/algorithm/gepa/lib/gepa_utils.py +117 -0
  82. gatewaysdk/algorithm/gepa/lib/logging/__init__.py +0 -0
  83. gatewaysdk/algorithm/gepa/lib/logging/experiment_tracker.py +187 -0
  84. gatewaysdk/algorithm/gepa/lib/logging/logger.py +75 -0
  85. gatewaysdk/algorithm/gepa/lib/logging/utils.py +103 -0
  86. gatewaysdk/algorithm/gepa/lib/proposer/__init__.py +0 -0
  87. gatewaysdk/algorithm/gepa/lib/proposer/base.py +31 -0
  88. gatewaysdk/algorithm/gepa/lib/proposer/merge.py +357 -0
  89. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/__init__.py +0 -0
  90. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/base.py +49 -0
  91. gatewaysdk/algorithm/gepa/lib/proposer/reflective_mutation/reflective_mutation.py +176 -0
  92. gatewaysdk/algorithm/gepa/lib/py.typed +0 -0
  93. gatewaysdk/algorithm/gepa/lib/strategies/__init__.py +0 -0
  94. gatewaysdk/algorithm/gepa/lib/strategies/batch_sampler.py +77 -0
  95. gatewaysdk/algorithm/gepa/lib/strategies/candidate_selector.py +50 -0
  96. gatewaysdk/algorithm/gepa/lib/strategies/component_selector.py +36 -0
  97. gatewaysdk/algorithm/gepa/lib/strategies/eval_policy.py +64 -0
  98. gatewaysdk/algorithm/gepa/lib/strategies/instruction_proposal.py +126 -0
  99. gatewaysdk/algorithm/gepa/lib/utils/__init__.py +10 -0
  100. gatewaysdk/algorithm/gepa/lib/utils/stop_condition.py +196 -0
  101. gatewaysdk/algorithm/gepa/tracing.py +105 -0
  102. gatewaysdk/algorithm/utils.py +177 -0
  103. gatewaysdk/algorithm/verl/__init__.py +5 -0
  104. gatewaysdk/algorithm/verl/interface.py +202 -0
  105. gatewaysdk/automations.py +111 -0
  106. gatewaysdk/benchmark_hub/README.md +88 -0
  107. gatewaysdk/benchmark_hub/__init__.py +119 -0
  108. gatewaysdk/benchmark_hub/_archive.py +189 -0
  109. gatewaysdk/benchmark_hub/_tar.py +6 -0
  110. gatewaysdk/benchmark_hub/client.py +992 -0
  111. gatewaysdk/benchmark_hub/dispatch_shard.py +34 -0
  112. gatewaysdk/benchmark_hub/eval_config.py +20 -0
  113. gatewaysdk/benchmark_hub/evals.py +351 -0
  114. gatewaysdk/benchmark_hub/harbor_adapter.py +673 -0
  115. gatewaysdk/benchmark_hub/path_utils.py +81 -0
  116. gatewaysdk/benchmark_hub/save_utils.py +101 -0
  117. gatewaysdk/benchmark_hub/verifiers_adapter.py +327 -0
  118. gatewaysdk/benchmark_hub/versioning.py +72 -0
  119. gatewaysdk/build.py +515 -0
  120. gatewaysdk/cli/__init__.py +58 -0
  121. gatewaysdk/cli/agent_runner.py +132 -0
  122. gatewaysdk/cli/http_client.py +115 -0
  123. gatewaysdk/cli/platform.py +4086 -0
  124. gatewaysdk/cli/prometheus.py +115 -0
  125. gatewaysdk/cli/release_gate.py +215 -0
  126. gatewaysdk/cli/store.py +131 -0
  127. gatewaysdk/cli/vllm.py +29 -0
  128. gatewaysdk/client.py +406 -0
  129. gatewaysdk/config.py +348 -0
  130. gatewaysdk/connectors/__init__.py +25 -0
  131. gatewaysdk/connectors/client.py +203 -0
  132. gatewaysdk/connectors/skill.py +25 -0
  133. gatewaysdk/connectors/template.py +106 -0
  134. gatewaysdk/context.py +606 -0
  135. gatewaysdk/emitter/__init__.py +43 -0
  136. gatewaysdk/emitter/annotation.py +370 -0
  137. gatewaysdk/emitter/exception.py +54 -0
  138. gatewaysdk/emitter/message.py +61 -0
  139. gatewaysdk/emitter/object.py +117 -0
  140. gatewaysdk/emitter/reward.py +320 -0
  141. gatewaysdk/env_var.py +156 -0
  142. gatewaysdk/environment/__init__.py +108 -0
  143. gatewaysdk/environment/_bundle.py +281 -0
  144. gatewaysdk/environment/_harbor.py +276 -0
  145. gatewaysdk/environment/_materialize.py +97 -0
  146. gatewaysdk/environment/_tar.py +33 -0
  147. gatewaysdk/environment/_world.py +346 -0
  148. gatewaysdk/environment/core.py +527 -0
  149. gatewaysdk/environment/errors.py +58 -0
  150. gatewaysdk/environment/runtime.py +150 -0
  151. gatewaysdk/environment/schema/__init__.py +35 -0
  152. gatewaysdk/environment/schema/__main__.py +225 -0
  153. gatewaysdk/environment/schema/_slack_fidelity.py +116 -0
  154. gatewaysdk/environment/schema/_slack_scenario.py +183 -0
  155. gatewaysdk/environment/schema/api.py +1628 -0
  156. gatewaysdk/environment/schema/batch.py +755 -0
  157. gatewaysdk/environment/schema/compiler.py +615 -0
  158. gatewaysdk/environment/schema/conform.py +428 -0
  159. gatewaysdk/environment/schema/connector.py +777 -0
  160. gatewaysdk/environment/schema/connectors/apple-business-manager/handlers.py +17 -0
  161. gatewaysdk/environment/schema/connectors/apple-business-manager/parity.json +28 -0
  162. gatewaysdk/environment/schema/connectors/apple-business-manager/provenance.json +233 -0
  163. gatewaysdk/environment/schema/connectors/apple-business-manager/scope.toml +112 -0
  164. gatewaysdk/environment/schema/connectors/apple-business-manager/world.json +1380 -0
  165. gatewaysdk/environment/schema/connectors/base.json +28 -0
  166. gatewaysdk/environment/schema/connectors/custom/handlers.py +18 -0
  167. gatewaysdk/environment/schema/connectors/custom/world.json +123 -0
  168. gatewaysdk/environment/schema/connectors/github/handlers.py +81 -0
  169. gatewaysdk/environment/schema/connectors/github/parity.json +37 -0
  170. gatewaysdk/environment/schema/connectors/github/provenance.json +134 -0
  171. gatewaysdk/environment/schema/connectors/github/scope.toml +158 -0
  172. gatewaysdk/environment/schema/connectors/github/world.json +5869 -0
  173. gatewaysdk/environment/schema/connectors/google-calendar/handlers.py +23 -0
  174. gatewaysdk/environment/schema/connectors/google-calendar/world.json +209 -0
  175. gatewaysdk/environment/schema/connectors/google-drive/handlers.py +18 -0
  176. gatewaysdk/environment/schema/connectors/google-drive/world.json +286 -0
  177. gatewaysdk/environment/schema/connectors/jamf/handlers.py +34 -0
  178. gatewaysdk/environment/schema/connectors/jamf/parity.json +49 -0
  179. gatewaysdk/environment/schema/connectors/jamf/provenance.json +181 -0
  180. gatewaysdk/environment/schema/connectors/jamf/scope.toml +128 -0
  181. gatewaysdk/environment/schema/connectors/jamf/world.json +2218 -0
  182. gatewaysdk/environment/schema/connectors/jira/handlers.py +28 -0
  183. gatewaysdk/environment/schema/connectors/jira/world.json +389 -0
  184. gatewaysdk/environment/schema/connectors/kandji/handlers.py +38 -0
  185. gatewaysdk/environment/schema/connectors/kandji/parity.json +29 -0
  186. gatewaysdk/environment/schema/connectors/kandji/provenance.json +152 -0
  187. gatewaysdk/environment/schema/connectors/kandji/scope.toml +120 -0
  188. gatewaysdk/environment/schema/connectors/kandji/world.json +765 -0
  189. gatewaysdk/environment/schema/connectors/linear/handlers.py +20 -0
  190. gatewaysdk/environment/schema/connectors/linear/world.json +363 -0
  191. gatewaysdk/environment/schema/connectors/microsoft-teams/fidelity.json +45 -0
  192. gatewaysdk/environment/schema/connectors/microsoft-teams/handlers.py +1 -0
  193. gatewaysdk/environment/schema/connectors/microsoft-teams/provenance.json +851 -0
  194. gatewaysdk/environment/schema/connectors/microsoft-teams/scope.md +231 -0
  195. gatewaysdk/environment/schema/connectors/microsoft-teams/teams-types.json +1710 -0
  196. gatewaysdk/environment/schema/connectors/microsoft-teams/world.json +858 -0
  197. gatewaysdk/environment/schema/connectors/netsuite/handlers.py +32 -0
  198. gatewaysdk/environment/schema/connectors/netsuite/parity.json +50 -0
  199. gatewaysdk/environment/schema/connectors/netsuite/provenance.json +137 -0
  200. gatewaysdk/environment/schema/connectors/netsuite/scope.toml +78 -0
  201. gatewaysdk/environment/schema/connectors/netsuite/world.json +16243 -0
  202. gatewaysdk/environment/schema/connectors/salesforce/handlers.py +806 -0
  203. gatewaysdk/environment/schema/connectors/salesforce/parity.json +46 -0
  204. gatewaysdk/environment/schema/connectors/salesforce/provenance.json +143 -0
  205. gatewaysdk/environment/schema/connectors/salesforce/scope.toml +174 -0
  206. gatewaysdk/environment/schema/connectors/salesforce/world.json +4695 -0
  207. gatewaysdk/environment/schema/connectors/slack/MODEL.md +236 -0
  208. gatewaysdk/environment/schema/connectors/slack/capabilities.json +1039 -0
  209. gatewaysdk/environment/schema/connectors/slack/handlers.py +762 -0
  210. gatewaysdk/environment/schema/connectors/slack/parity.json +65 -0
  211. gatewaysdk/environment/schema/connectors/slack/provenance.json +294 -0
  212. gatewaysdk/environment/schema/connectors/slack/scope.toml +44 -0
  213. gatewaysdk/environment/schema/connectors/slack/world.json +4993 -0
  214. gatewaysdk/environment/schema/connectors/workday/handlers.py +75 -0
  215. gatewaysdk/environment/schema/connectors/workday/parity.json +36 -0
  216. gatewaysdk/environment/schema/connectors/workday/provenance.json +179 -0
  217. gatewaysdk/environment/schema/connectors/workday/scope.toml +180 -0
  218. gatewaysdk/environment/schema/connectors/workday/world.json +806 -0
  219. gatewaysdk/environment/schema/data.py +593 -0
  220. gatewaysdk/environment/schema/extract.py +263 -0
  221. gatewaysdk/environment/schema/host.py +2437 -0
  222. gatewaysdk/environment/schema/host_surfaces.py +275 -0
  223. gatewaysdk/environment/schema/platform.py +1272 -0
  224. gatewaysdk/environment/schema/scaffold.py +250 -0
  225. gatewaysdk/environment/schema/skill.py +118 -0
  226. gatewaysdk/environment/schema/skills/agents/connector-template-author.md +202 -0
  227. gatewaysdk/environment/schema/skills/connector-schema-authoring/CONNECTORS.md +331 -0
  228. gatewaysdk/environment/schema/skills/connector-schema-authoring/CONVENTIONS.md +100 -0
  229. gatewaysdk/environment/schema/skills/connector-schema-authoring/SKILL.md +313 -0
  230. gatewaysdk/environment/schema/skills/world-data-ingestion/ROWS.md +223 -0
  231. gatewaysdk/environment/schema/skills/world-data-ingestion/SKILL.md +293 -0
  232. gatewaysdk/environment/schema/skills/worlds-getting-started/SKILL.md +390 -0
  233. gatewaysdk/environment/schema/slack.py +757 -0
  234. gatewaysdk/environment/schema/snapshot.py +479 -0
  235. gatewaysdk/environment/schema/store.py +904 -0
  236. gatewaysdk/environment/schema/tasks.py +525 -0
  237. gatewaysdk/environment/schema/tools_world.py +322 -0
  238. gatewaysdk/environment/schema/validation.py +577 -0
  239. gatewaysdk/environment/schema/worker.py +78 -0
  240. gatewaysdk/environment/schema/workers.py +500 -0
  241. gatewaysdk/environment/schema/world_tests.py +336 -0
  242. gatewaysdk/environments/__init__.py +24 -0
  243. gatewaysdk/environments/client.py +486 -0
  244. gatewaysdk/environments/types.py +318 -0
  245. gatewaysdk/execution/__init__.py +15 -0
  246. gatewaysdk/execution/base.py +64 -0
  247. gatewaysdk/execution/client_server.py +443 -0
  248. gatewaysdk/execution/events.py +69 -0
  249. gatewaysdk/execution/inter_process.py +16 -0
  250. gatewaysdk/execution/shared_memory.py +282 -0
  251. gatewaysdk/experiments/__init__.py +90 -0
  252. gatewaysdk/experiments/assignment.py +177 -0
  253. gatewaysdk/experiments/client.py +877 -0
  254. gatewaysdk/experiments/exposure.py +222 -0
  255. gatewaysdk/experiments/types.py +81 -0
  256. gatewaysdk/importers/__init__.py +49 -0
  257. gatewaysdk/importers/_normalize.py +91 -0
  258. gatewaysdk/importers/builder.py +173 -0
  259. gatewaysdk/importers/client.py +95 -0
  260. gatewaysdk/importers/langsmith.py +196 -0
  261. gatewaysdk/importers/recipes.py +249 -0
  262. gatewaysdk/instrumentation/__init__.py +300 -0
  263. gatewaysdk/instrumentation/agentops.py +314 -0
  264. gatewaysdk/instrumentation/agentops_langchain.py +45 -0
  265. gatewaysdk/instrumentation/base.py +119 -0
  266. gatewaysdk/instrumentation/litellm.py +83 -0
  267. gatewaysdk/instrumentation/registry.py +273 -0
  268. gatewaysdk/instrumentation/vllm.py +81 -0
  269. gatewaysdk/instrumentation/weave.py +500 -0
  270. gatewaysdk/integrations/__init__.py +15 -0
  271. gatewaysdk/integrations/gateway/__init__.py +11 -0
  272. gatewaysdk/integrations/gateway/client.py +171 -0
  273. gatewaysdk/integrations/tool_access.py +549 -0
  274. gatewaysdk/litagent/__init__.py +11 -0
  275. gatewaysdk/litagent/decorator.py +536 -0
  276. gatewaysdk/litagent/litagent.py +252 -0
  277. gatewaysdk/llm_proxy.py +1742 -0
  278. gatewaysdk/logging.py +370 -0
  279. gatewaysdk/memory.py +278 -0
  280. gatewaysdk/personas.py +186 -0
  281. gatewaysdk/platform/__init__.py +17 -0
  282. gatewaysdk/platform/builder.py +221 -0
  283. gatewaysdk/platform/compatibility.py +67 -0
  284. gatewaysdk/platform/manifest.py +185 -0
  285. gatewaysdk/platform/orchestrator.py +901 -0
  286. gatewaysdk/platform/registry.py +122 -0
  287. gatewaysdk/platform/worker.py +864 -0
  288. gatewaysdk/replay/__init__.py +1032 -0
  289. gatewaysdk/replay/pytest.py +56 -0
  290. gatewaysdk/reward.py +7 -0
  291. gatewaysdk/run.py +1781 -0
  292. gatewaysdk/runner/__init__.py +11 -0
  293. gatewaysdk/runner/agent.py +878 -0
  294. gatewaysdk/runner/base.py +182 -0
  295. gatewaysdk/runner/legacy.py +309 -0
  296. gatewaysdk/security.py +700 -0
  297. gatewaysdk/semconv.py +170 -0
  298. gatewaysdk/server.py +399 -0
  299. gatewaysdk/sessions.py +282 -0
  300. gatewaysdk/store/__init__.py +45 -0
  301. gatewaysdk/store/base.py +908 -0
  302. gatewaysdk/store/client_server.py +2093 -0
  303. gatewaysdk/store/collection/__init__.py +30 -0
  304. gatewaysdk/store/collection/base.py +587 -0
  305. gatewaysdk/store/collection/memory.py +970 -0
  306. gatewaysdk/store/collection/mongo.py +1412 -0
  307. gatewaysdk/store/collection_based.py +1823 -0
  308. gatewaysdk/store/gateway.py +983 -0
  309. gatewaysdk/store/gateway_listener.py +465 -0
  310. gatewaysdk/store/listener.py +58 -0
  311. gatewaysdk/store/memory.py +396 -0
  312. gatewaysdk/store/mongo.py +165 -0
  313. gatewaysdk/store/redis_stream.py +517 -0
  314. gatewaysdk/store/sqlite.py +3 -0
  315. gatewaysdk/store/threading.py +370 -0
  316. gatewaysdk/store/utils.py +142 -0
  317. gatewaysdk/tracer/__init__.py +14 -0
  318. gatewaysdk/tracer/base.py +286 -0
  319. gatewaysdk/tracer/dummy.py +106 -0
  320. gatewaysdk/tracer/otel.py +559 -0
  321. gatewaysdk/tracing/__init__.py +110 -0
  322. gatewaysdk/tracing/api.py +808 -0
  323. gatewaysdk/tracing/attributes.py +9 -0
  324. gatewaysdk/tracing/context.py +272 -0
  325. gatewaysdk/tracing/exporters/__init__.py +10 -0
  326. gatewaysdk/tracing/exporters/gateway.py +228 -0
  327. gatewaysdk/tracing/identity.py +288 -0
  328. gatewaysdk/tracing/init.py +620 -0
  329. gatewaysdk/tracing/instrumentors/__init__.py +15 -0
  330. gatewaysdk/tracing/instrumentors/claude_agent_sdk.py +766 -0
  331. gatewaysdk/tracing/instrumentors/instrumentation_principles.md +294 -0
  332. gatewaysdk/tracing/instrumentors/registry.py +352 -0
  333. gatewaysdk/tracing/mapping.py +729 -0
  334. gatewaysdk/tracing/processors.py +393 -0
  335. gatewaysdk/tracing/push.py +617 -0
  336. gatewaysdk/tracing/push_models.py +247 -0
  337. gatewaysdk/tracing/semconv.py +294 -0
  338. gatewaysdk/tracing/span_builder.py +356 -0
  339. gatewaysdk/trainer/__init__.py +6 -0
  340. gatewaysdk/trainer/init_utils.py +263 -0
  341. gatewaysdk/trainer/legacy.py +359 -0
  342. gatewaysdk/trainer/registry.py +12 -0
  343. gatewaysdk/trainer/trainer.py +638 -0
  344. gatewaysdk/types/__init__.py +63 -0
  345. gatewaysdk/types/core.py +556 -0
  346. gatewaysdk/types/resources.py +204 -0
  347. gatewaysdk/types/tracer.py +515 -0
  348. gatewaysdk/types/tracing.py +162 -0
  349. gatewaysdk/users.py +251 -0
  350. gatewaysdk/utils/__init__.py +1 -0
  351. gatewaysdk/utils/id.py +18 -0
  352. gatewaysdk/utils/metrics.py +1025 -0
  353. gatewaysdk/utils/otel.py +550 -0
  354. gatewaysdk/utils/otlp.py +556 -0
  355. gatewaysdk/utils/redact.py +22 -0
  356. gatewaysdk/utils/server_launcher.py +1045 -0
  357. gatewaysdk/utils/system_snapshot.py +90 -0
  358. gatewaysdk/verl/__init__.py +8 -0
  359. gatewaysdk/verl/__main__.py +6 -0
  360. gatewaysdk/verl/async_server.py +46 -0
  361. gatewaysdk/verl/config.yaml +27 -0
  362. gatewaysdk/verl/daemon.py +1154 -0
  363. gatewaysdk/verl/dataset.py +44 -0
  364. gatewaysdk/verl/entrypoint.py +248 -0
  365. gatewaysdk/verl/trainer.py +549 -0
  366. gatewaysdk/world_browser.py +748 -0
  367. gatewaysdk/world_data.py +453 -0
  368. gatewaysdk/world_sessions.py +978 -0
  369. gatewaysdk/world_tasks.py +285 -0
  370. gatewaysdk/world_tools.py +115 -0
  371. gatewaysdk/worlds.py +639 -0
  372. gatewaysdk-0.3.2.dist-info/METADATA +236 -0
  373. gatewaysdk-0.3.2.dist-info/RECORD +376 -0
  374. gatewaysdk-0.3.2.dist-info/WHEEL +4 -0
  375. gatewaysdk-0.3.2.dist-info/entry_points.txt +5 -0
  376. gatewaysdk-0.3.2.dist-info/licenses/LICENSE +19 -0
@@ -0,0 +1,356 @@
1
+ # Copyright (c) Gateway. All rights reserved.
2
+
3
+ """OTel span builder for JSON push-to-trace.
4
+
5
+ Creates OpenTelemetry spans from resolved mapping data. Isolated from
6
+ the mapping engine -- takes already-validated, already-resolved field
7
+ dicts and produces real spans with proper parent-child linking.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import logging
14
+ import time
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ from opentelemetry import context as otel_context
18
+ from opentelemetry import trace as otel_trace
19
+
20
+ from . import semconv
21
+ from .mapping import ChildMapping, coerce_timestamp, resolve_path
22
+ from .push_models import SpanPreview, ValidationIssue
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+ # Default timestamp: "now" in nanoseconds
27
+ _NANOS_PER_SECOND = 1_000_000_000
28
+
29
+
30
+ def _now_ns() -> int:
31
+ return int(time.time() * _NANOS_PER_SECOND)
32
+
33
+
34
+ def _safe_json(value: Any) -> str:
35
+ """Serialize a value to JSON string for span attributes."""
36
+ if isinstance(value, str):
37
+ return value
38
+ try:
39
+ return json.dumps(value)
40
+ except (TypeError, ValueError):
41
+ logger.warning(
42
+ "Value of type %s is not JSON-serializable, using str() fallback: %s",
43
+ type(value).__name__,
44
+ repr(value)[:100],
45
+ )
46
+ return str(value)
47
+
48
+
49
+ # =============================================================================
50
+ # Span Building
51
+ # =============================================================================
52
+
53
+
54
+ def build_trace_spans(
55
+ data: dict,
56
+ fields: Dict[str, Any],
57
+ child_mapping: Optional[ChildMapping],
58
+ tracer: Optional[otel_trace.Tracer] = None,
59
+ extra_attributes: Optional[Dict[str, Any]] = None,
60
+ timestamp_unit: str = "auto",
61
+ ) -> tuple[str, int, List[ValidationIssue]]:
62
+ """Create OTel spans for a trace and its children.
63
+
64
+ Args:
65
+ data: The original JSON data dict (for resolving child fields).
66
+ fields: Merged trace-level fields (name, input, output, etc.).
67
+ child_mapping: Optional mapping for children observations.
68
+ tracer: OTel tracer to use. Defaults to the global gatewaysdk tracer.
69
+ extra_attributes: Additional OTel span attributes to set on the root span.
70
+
71
+ Returns:
72
+ (trace_id, observation_count, warnings) -- the hex trace ID, number of
73
+ child observations created, and any runtime warnings.
74
+ """
75
+ if tracer is None:
76
+ tracer = otel_trace.get_tracer("gatewaysdk.tracing.push")
77
+
78
+ start_ns = coerce_timestamp(fields.get("timestamp"), unit=timestamp_unit) or _now_ns()
79
+
80
+ # Build root span attributes
81
+ root_attrs = _build_trace_attributes(fields)
82
+ if extra_attributes:
83
+ root_attrs.update(extra_attributes)
84
+
85
+ root_span = tracer.start_span(
86
+ name=fields.get("name") or "push",
87
+ start_time=start_ns,
88
+ attributes=root_attrs,
89
+ )
90
+
91
+ observation_count = 0
92
+ runtime_warnings: List[ValidationIssue] = []
93
+
94
+ # Build children
95
+ if child_mapping is not None:
96
+ found, children_data = resolve_path(data, child_mapping.path)
97
+ if found and isinstance(children_data, list):
98
+ root_ctx = otel_trace.set_span_in_context(root_span)
99
+ observation_count, child_warnings = _build_children(
100
+ children_data,
101
+ child_mapping,
102
+ tracer,
103
+ root_ctx,
104
+ start_ns,
105
+ timestamp_unit=timestamp_unit,
106
+ )
107
+ runtime_warnings.extend(child_warnings)
108
+
109
+ # End root span
110
+ end_ns = _now_ns()
111
+ root_span.end(end_time=end_ns)
112
+
113
+ # Extract trace ID
114
+ span_context = root_span.get_span_context()
115
+ trace_id = format(span_context.trace_id, "032x")
116
+
117
+ return trace_id, observation_count, runtime_warnings
118
+
119
+
120
+ def _build_trace_attributes(fields: Dict[str, Any]) -> Dict[str, Any]:
121
+ """Build OTel span attributes for the root trace span."""
122
+ attrs: Dict[str, Any] = {}
123
+
124
+ if fields.get("name"):
125
+ attrs[semconv.TRACE_NAME] = fields["name"]
126
+ if fields.get("input") is not None:
127
+ attrs[semconv.TRACE_INPUT] = _safe_json(fields["input"])
128
+ if fields.get("output") is not None:
129
+ attrs[semconv.TRACE_OUTPUT] = _safe_json(fields["output"])
130
+ if fields.get("metadata") is not None:
131
+ attrs[semconv.TRACE_METADATA] = _safe_json(fields["metadata"])
132
+ if fields.get("tags"):
133
+ attrs[semconv.TRACE_TAGS] = _safe_json(fields["tags"])
134
+ if fields.get("user_id"):
135
+ attrs[semconv.USER_ID] = fields["user_id"]
136
+ if fields.get("session_id"):
137
+ attrs[semconv.SESSION_ID] = fields["session_id"]
138
+ if fields.get("run_id"):
139
+ attrs[semconv.RUN_ID] = fields["run_id"]
140
+ if fields.get("environment"):
141
+ attrs[semconv.ENVIRONMENT] = fields["environment"]
142
+
143
+ return attrs
144
+
145
+
146
+ def _build_children(
147
+ children_data: List[dict],
148
+ child_mapping: ChildMapping,
149
+ tracer: otel_trace.Tracer,
150
+ parent_ctx: otel_context.Context,
151
+ parent_start_ns: int,
152
+ timestamp_unit: str = "auto",
153
+ ) -> tuple[int, List[ValidationIssue]]:
154
+ """Create child observation spans under the parent context.
155
+
156
+ Returns (observation_count, warnings).
157
+ """
158
+ count = 0
159
+ warnings: List[ValidationIssue] = []
160
+
161
+ for i, child_dict in enumerate(children_data):
162
+ if not isinstance(child_dict, dict):
163
+ warnings.append(
164
+ ValidationIssue(
165
+ field="children",
166
+ path=f"{child_mapping.path}[{i}]",
167
+ issue="invalid_child",
168
+ message=f"Children item at index {i} is {type(child_dict).__name__}, expected dict. Skipped.",
169
+ )
170
+ )
171
+ continue
172
+
173
+ child_fields, field_warnings = _extract_child_fields(child_dict, child_mapping, timestamp_unit=timestamp_unit)
174
+ warnings.extend(field_warnings)
175
+
176
+ child_start = child_fields.get("start_time_ns") or (parent_start_ns + i)
177
+ child_end = child_fields.get("end_time_ns")
178
+
179
+ child_attrs = _build_observation_attributes(child_fields)
180
+
181
+ child_span = tracer.start_span(
182
+ name=child_fields.get("name") or f"observation-{i}",
183
+ context=parent_ctx,
184
+ start_time=child_start,
185
+ attributes=child_attrs,
186
+ )
187
+
188
+ # Recurse into nested children if the mapping defines them
189
+ nested_count = 0
190
+ if child_mapping.children is not None:
191
+ found, nested_data = resolve_path(child_dict, child_mapping.children.path)
192
+ if found and isinstance(nested_data, list):
193
+ child_ctx = otel_trace.set_span_in_context(child_span)
194
+ nested_count, nested_warnings = _build_children(
195
+ nested_data,
196
+ child_mapping.children,
197
+ tracer,
198
+ child_ctx,
199
+ child_start,
200
+ timestamp_unit=timestamp_unit,
201
+ )
202
+ warnings.extend(nested_warnings)
203
+
204
+ child_span.end(end_time=child_end or _now_ns())
205
+ count += 1 + nested_count
206
+
207
+ return count, warnings
208
+
209
+
210
+ def _extract_child_fields(
211
+ child_dict: dict,
212
+ mapping: ChildMapping,
213
+ timestamp_unit: str = "auto",
214
+ ) -> tuple[Dict[str, Any], List[ValidationIssue]]:
215
+ """Extract mapped fields from a single child dict.
216
+
217
+ Returns (fields, warnings).
218
+ """
219
+ fields: Dict[str, Any] = {}
220
+ warnings: List[ValidationIssue] = []
221
+
222
+ simple_fields = [
223
+ "name",
224
+ "input",
225
+ "output",
226
+ "type",
227
+ "model",
228
+ "metadata",
229
+ "level",
230
+ "usage",
231
+ "cost",
232
+ "model_parameters",
233
+ "status_message",
234
+ "prompt_name",
235
+ "prompt_version",
236
+ "attributes",
237
+ ]
238
+ for field in simple_fields:
239
+ dot_path = getattr(mapping, field, None)
240
+ if dot_path is not None:
241
+ found, value = resolve_path(child_dict, dot_path)
242
+ if found:
243
+ fields[field] = value
244
+
245
+ # Timestamps need coercion
246
+ for ts_field in ("start_time", "end_time"):
247
+ dot_path = getattr(mapping, ts_field, None)
248
+ if dot_path is not None:
249
+ found, value = resolve_path(child_dict, dot_path)
250
+ if found:
251
+ coerced = coerce_timestamp(value, unit=timestamp_unit)
252
+ if coerced is None and value is not None:
253
+ warnings.append(
254
+ ValidationIssue(
255
+ field=f"children.{ts_field}",
256
+ path=dot_path,
257
+ issue="timestamp_coercion_failed",
258
+ message=f"Could not parse timestamp value: {value!r}. Using fallback.",
259
+ )
260
+ )
261
+ fields[f"{ts_field}_ns"] = coerced
262
+
263
+ return fields, warnings
264
+
265
+
266
+ def _build_observation_attributes(fields: Dict[str, Any]) -> Dict[str, Any]:
267
+ """Build OTel span attributes for an observation span."""
268
+ attrs: Dict[str, Any] = {}
269
+
270
+ if fields.get("input") is not None:
271
+ attrs[semconv.OBSERVATION_INPUT] = _safe_json(fields["input"])
272
+ if fields.get("output") is not None:
273
+ attrs[semconv.OBSERVATION_OUTPUT] = _safe_json(fields["output"])
274
+ if fields.get("type"):
275
+ attrs[semconv.OBSERVATION_TYPE] = fields["type"].upper()
276
+ if fields.get("model"):
277
+ attrs[semconv.MODEL_NAME] = fields["model"]
278
+ # Presence of model implies GENERATION type (unless explicitly set)
279
+ if not fields.get("type"):
280
+ attrs[semconv.OBSERVATION_TYPE] = "GENERATION"
281
+ if fields.get("metadata") is not None:
282
+ attrs[semconv.OBSERVATION_METADATA] = _safe_json(fields["metadata"])
283
+ if fields.get("level"):
284
+ attrs[semconv.OBSERVATION_LEVEL] = fields["level"].upper()
285
+ if fields.get("status_message"):
286
+ attrs[semconv.OBSERVATION_STATUS_MESSAGE] = fields["status_message"]
287
+ if fields.get("model_parameters") is not None:
288
+ attrs[semconv.MODEL_PARAMETERS] = _safe_json(fields["model_parameters"])
289
+
290
+ # Usage and cost use the langfuse-compatible attributes
291
+ if fields.get("usage") is not None:
292
+ attrs["gateway.observation.usage_details"] = _safe_json(fields["usage"])
293
+ if fields.get("cost") is not None:
294
+ attrs["gateway.observation.cost_details"] = _safe_json(fields["cost"])
295
+
296
+ # Prompt reference
297
+ if fields.get("prompt_name"):
298
+ attrs["gateway.observation.prompt.name"] = fields["prompt_name"]
299
+ if fields.get("prompt_version") is not None:
300
+ attrs["gateway.observation.prompt.version"] = fields["prompt_version"]
301
+
302
+ # Extra attributes escape hatch
303
+ extra = fields.get("attributes")
304
+ if isinstance(extra, dict):
305
+ attrs.update(extra)
306
+
307
+ return attrs
308
+
309
+
310
+ # =============================================================================
311
+ # Preview Building (no OTel dependency)
312
+ # =============================================================================
313
+
314
+
315
+ def build_trace_preview(
316
+ data: dict,
317
+ fields: Dict[str, Any],
318
+ child_mapping: Optional[ChildMapping],
319
+ ) -> List[SpanPreview]:
320
+ """Build SpanPreview objects for children (no OTel spans created).
321
+
322
+ Returns list of SpanPreview for the children.
323
+ """
324
+ if child_mapping is None:
325
+ return []
326
+
327
+ found, children_data = resolve_path(data, child_mapping.path)
328
+ if not found or not isinstance(children_data, list):
329
+ return []
330
+
331
+ previews = []
332
+ for i, child_dict in enumerate(children_data):
333
+ if not isinstance(child_dict, dict):
334
+ continue
335
+
336
+ child_fields, _ = _extract_child_fields(child_dict, child_mapping)
337
+
338
+ nested = []
339
+ if child_mapping.children is not None:
340
+ nested = build_trace_preview(child_dict, child_fields, child_mapping.children)
341
+
342
+ previews.append(
343
+ SpanPreview(
344
+ name=child_fields.get("name") or f"observation-{i}",
345
+ type=child_fields.get("type"),
346
+ input=child_fields.get("input"),
347
+ output=child_fields.get("output"),
348
+ model=child_fields.get("model"),
349
+ metadata=child_fields.get("metadata"),
350
+ start_time=str(child_fields.get("start_time_ns")) if child_fields.get("start_time_ns") else None,
351
+ end_time=str(child_fields.get("end_time_ns")) if child_fields.get("end_time_ns") else None,
352
+ children=nested,
353
+ )
354
+ )
355
+
356
+ return previews
@@ -0,0 +1,6 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ from .init_utils import build_component
4
+ from .trainer import Trainer
5
+
6
+ __all__ = ["Trainer", "build_component"]
@@ -0,0 +1,263 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ """Utility helpers for dynamic component initialization within the trainer."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import importlib
8
+ import inspect
9
+ from typing import Any, Callable, Dict, Optional, TypeVar, Union, cast, overload
10
+
11
+ OptionalDefaults = Dict[str, Callable[[], Any] | Any]
12
+ T = TypeVar("T")
13
+
14
+
15
+ def load_class(path: str) -> type[Any]:
16
+ """Load a class from its fully qualified import path."""
17
+ module_name, class_name = path.rsplit(".", 1)
18
+ module = importlib.import_module(module_name)
19
+ return getattr(module, class_name)
20
+
21
+
22
+ def instantiate_component(
23
+ cls: type[Any],
24
+ provided_kwargs: Optional[Dict[str, Any]] = None,
25
+ optional_defaults: Optional[OptionalDefaults] = None,
26
+ ) -> Any:
27
+ """Instantiate `cls`, filling optional kwargs when the constructor accepts them."""
28
+ kwargs = dict(provided_kwargs or {})
29
+ if optional_defaults:
30
+ signature = inspect.signature(cls.__init__)
31
+ for name, value in optional_defaults.items():
32
+ if name in kwargs or name not in signature.parameters:
33
+ continue
34
+ kwargs[name] = value() if callable(value) else value
35
+ return cls(**kwargs)
36
+
37
+
38
+ def instantiate_from_spec(
39
+ spec: Union[str, Dict[str, Any]],
40
+ *,
41
+ spec_name: str,
42
+ optional_defaults: Optional[OptionalDefaults] = None,
43
+ dict_requires_type: bool = True,
44
+ dict_default_cls: type[Any] | None = None,
45
+ registry: Optional[Dict[str, str]] = None,
46
+ ) -> Any:
47
+ """Instantiate a component from a string or dict spec."""
48
+ if isinstance(spec, str):
49
+ type_path = registry.get(spec, spec) if registry else spec
50
+ cls = load_class(type_path)
51
+ return instantiate_component(cls, optional_defaults=optional_defaults)
52
+
53
+ if isinstance(spec, dict): # pyright: ignore[reportUnnecessaryIsInstance]
54
+ spec_conf = dict(spec)
55
+ type_path = spec_conf.pop("type", None)
56
+ if type_path is None and registry and "name" in spec_conf:
57
+ type_path = registry.get(spec_conf.pop("name"))
58
+ elif registry and type_path is not None:
59
+ type_path = registry.get(type_path, type_path)
60
+ if type_path is None:
61
+ if dict_requires_type:
62
+ raise ValueError(f"{spec_name} dict must have a 'type' key with the class full name")
63
+ if dict_default_cls is None:
64
+ raise ValueError(f"{spec_name} dict missing 'type' and no default class provided")
65
+ cls = dict_default_cls
66
+ else:
67
+ cls = load_class(type_path)
68
+ return instantiate_component(cls, spec_conf, optional_defaults)
69
+
70
+ raise TypeError(f"{spec_name} spec must be a string or dict (got {type(spec)}).")
71
+
72
+
73
+ def _ensure_expected_type(
74
+ instance: Any,
75
+ expected_type: type[T],
76
+ spec_name: str,
77
+ type_error_fmt: str | None,
78
+ ) -> T:
79
+ if not isinstance(instance, expected_type):
80
+ type_name = str(type(instance)) # type: ignore
81
+ if type_error_fmt:
82
+ raise TypeError(type_error_fmt.format(type_name=type_name, expected_type=expected_type.__name__))
83
+ raise TypeError(f"{spec_name} factory returned {type_name}, which is not a {expected_type.__name__} subclass.")
84
+ return instance
85
+
86
+
87
+ @overload
88
+ def build_component(
89
+ spec: Union[T, str, Dict[str, Any], type[T], Callable[[], T], None],
90
+ *,
91
+ expected_type: type[T],
92
+ spec_name: str,
93
+ default_factory: Callable[[], T],
94
+ allow_none: bool = ...,
95
+ optional_defaults: Optional[OptionalDefaults] = ...,
96
+ dict_requires_type: bool = ...,
97
+ dict_default_cls: type[T] | None = ...,
98
+ type_error_fmt: str | None = ...,
99
+ invalid_spec_error_fmt: str | None = ...,
100
+ registry: Optional[Dict[str, str]] = ...,
101
+ ) -> T: ...
102
+
103
+
104
+ @overload
105
+ def build_component(
106
+ spec: Union[T, str, Dict[str, Any], type[T], Callable[[], T], None],
107
+ *,
108
+ expected_type: type[T],
109
+ spec_name: str,
110
+ default_factory: None = ...,
111
+ allow_none: bool,
112
+ optional_defaults: Optional[OptionalDefaults] = ...,
113
+ dict_requires_type: bool = ...,
114
+ dict_default_cls: type[T] | None = ...,
115
+ type_error_fmt: str | None = ...,
116
+ invalid_spec_error_fmt: str | None = ...,
117
+ registry: Optional[Dict[str, str]] = ...,
118
+ ) -> T | None: ...
119
+
120
+
121
+ @overload
122
+ def build_component(
123
+ spec: Union[T, str, Dict[str, Any], type[T], Callable[[], T], None],
124
+ *,
125
+ expected_type: type[T],
126
+ spec_name: str,
127
+ default_factory: None = ...,
128
+ allow_none: bool = ...,
129
+ optional_defaults: Optional[OptionalDefaults] = ...,
130
+ dict_requires_type: bool = ...,
131
+ dict_default_cls: type[T] | None = ...,
132
+ type_error_fmt: str | None = ...,
133
+ invalid_spec_error_fmt: str | None = ...,
134
+ registry: Optional[Dict[str, str]] = ...,
135
+ ) -> T | None: ...
136
+
137
+
138
+ def build_component(
139
+ spec: Union[T, str, Dict[str, Any], type[T], Callable[[], T], None],
140
+ *,
141
+ expected_type: type[T],
142
+ spec_name: str,
143
+ default_factory: Callable[[], T] | None = None,
144
+ allow_none: bool = False,
145
+ optional_defaults: Optional[OptionalDefaults] = None,
146
+ dict_requires_type: bool = True,
147
+ dict_default_cls: type[T] | None = None,
148
+ type_error_fmt: str | None = None,
149
+ invalid_spec_error_fmt: str | None = None,
150
+ registry: Optional[Dict[str, str]] = None,
151
+ ) -> T | None:
152
+ """Build and return a component instance from a flexible specification.
153
+
154
+ This function provides a flexible way to create component instances from various
155
+ input formats including direct instances, class types, factory functions, import
156
+ paths, or configuration dictionaries.
157
+
158
+ Args:
159
+ spec: The component specification. Can be:
160
+ - An instance of expected_type (returned as-is)
161
+ - A string import path (e.g., 'module.Class') or registry key
162
+ - A dict with 'type' key (import path or registry key) and constructor kwargs
163
+ - A class type (will be instantiated)
164
+ - A factory function (will be called)
165
+ - None (uses default_factory or returns None if allow_none=True)
166
+ expected_type: The type that the resulting instance must be or inherit from.
167
+ spec_name: Descriptive name for the spec, used in error messages.
168
+ default_factory: Optional factory function called when spec is None.
169
+ allow_none: If True, allows None to be returned when spec is None and
170
+ no default_factory is provided.
171
+ optional_defaults: Dict mapping parameter names to default values or factory
172
+ functions that will be injected if the constructor accepts them.
173
+ dict_requires_type: If True, dict specs must include a 'type' key.
174
+ dict_default_cls: Default class to use for dict specs without a 'type' key
175
+ (only used when dict_requires_type=False).
176
+ type_error_fmt: Custom format string for type validation errors. Should include
177
+ {type_name} and {expected_type} placeholders.
178
+ invalid_spec_error_fmt: Custom format string for invalid spec type errors.
179
+ Should include {actual_type} and {expected_type} placeholders.
180
+ registry: Optional mapping of short names to fully qualified import paths.
181
+ When provided, string specs or dict 'type'/'name' entries are first
182
+ resolved through this registry before attempting to import.
183
+
184
+ Returns:
185
+ An instance of expected_type, or None if allow_none=True and spec is None
186
+ without a default_factory.
187
+
188
+ Raises:
189
+ TypeError: If the instantiated object is not an instance of expected_type.
190
+ ValueError: If spec is None and neither default_factory nor allow_none is set,
191
+ or if spec type is invalid, or if dict spec is invalid.
192
+
193
+ Examples:
194
+ >>> # Direct instance
195
+ >>> optimizer = build_component(AdamW(), expected_type=Optimizer, spec_name='optimizer')
196
+ >>>
197
+ >>> # String import path
198
+ >>> optimizer = build_component('torch.optim.AdamW', expected_type=Optimizer, spec_name='optimizer')
199
+ >>>
200
+ >>> # Dict with type and kwargs
201
+ >>> spec = {'type': 'torch.optim.AdamW', 'lr': 0.001}
202
+ >>> optimizer = build_component(spec, expected_type=Optimizer, spec_name='optimizer')
203
+ >>>
204
+ >>> # Class type
205
+ >>> optimizer = build_component(AdamW, expected_type=Optimizer, spec_name='optimizer')
206
+ >>>
207
+ >>> # Factory function
208
+ >>> optimizer = build_component(lambda: AdamW(lr=0.001), expected_type=Optimizer,
209
+ ... spec_name='optimizer')
210
+ """
211
+ if isinstance(spec, expected_type):
212
+ return cast(T, spec)
213
+
214
+ if spec is None:
215
+ if default_factory is not None:
216
+ instance = default_factory()
217
+ return _ensure_expected_type(instance, expected_type, spec_name, type_error_fmt)
218
+ if allow_none:
219
+ return None
220
+ raise ValueError(
221
+ invalid_spec_error_fmt.format(actual_type=type(spec), expected_type=expected_type.__name__)
222
+ if invalid_spec_error_fmt
223
+ else f"{spec_name} cannot be None."
224
+ )
225
+
226
+ if isinstance(spec, type) and issubclass(spec, expected_type):
227
+ instance = instantiate_component(spec, optional_defaults=optional_defaults)
228
+ return _ensure_expected_type(instance, expected_type, spec_name, type_error_fmt)
229
+
230
+ if callable(spec) and not isinstance(spec, type): # type: ignore
231
+ instance = spec()
232
+ return _ensure_expected_type(instance, expected_type, spec_name, type_error_fmt)
233
+
234
+ if isinstance(spec, str):
235
+ instance = instantiate_from_spec(
236
+ spec,
237
+ spec_name=spec_name,
238
+ optional_defaults=optional_defaults,
239
+ dict_requires_type=dict_requires_type,
240
+ dict_default_cls=dict_default_cls,
241
+ registry=registry,
242
+ )
243
+ return _ensure_expected_type(instance, expected_type, spec_name, type_error_fmt)
244
+
245
+ if isinstance(spec, dict):
246
+ instance = instantiate_from_spec(
247
+ spec, # type: ignore
248
+ spec_name=spec_name,
249
+ optional_defaults=optional_defaults,
250
+ dict_requires_type=dict_requires_type,
251
+ dict_default_cls=dict_default_cls,
252
+ registry=registry,
253
+ )
254
+ return _ensure_expected_type(instance, expected_type, spec_name, type_error_fmt)
255
+
256
+ if invalid_spec_error_fmt:
257
+ raise ValueError(invalid_spec_error_fmt.format(actual_type=type(spec), expected_type=expected_type.__name__)) # type: ignore
258
+
259
+ type_name = str(type(spec)) # type: ignore
260
+ raise ValueError(f"Invalid {spec_name} type: {type_name}. Expected {expected_type.__name__}, str, dict, or None.")
261
+
262
+
263
+ __all__ = ["OptionalDefaults", "build_component", "instantiate_component", "instantiate_from_spec", "load_class"]