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,808 @@
1
+ # Copyright (c) Gateway. All rights reserved.
2
+
3
+ """Context managers and decorators for GatewayDK tracing.
4
+
5
+ This module provides the user-facing API for creating spans:
6
+ - trace(): Create a root span (trace)
7
+ - span(): Create a child span
8
+ - tool(): Create a tool execution span
9
+
10
+ Both sync and async variants are provided.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import asyncio
16
+ import functools
17
+ import inspect
18
+ import json
19
+ import logging
20
+ from contextlib import asynccontextmanager, contextmanager
21
+ from typing import Any, AsyncGenerator, Callable, Generator, Optional, TypeVar, Union
22
+
23
+ from opentelemetry import trace as otel_trace
24
+ from opentelemetry.trace import Span, SpanKind, Status, StatusCode, Tracer
25
+
26
+ from . import semconv
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # Type variable for decorators
31
+ F = TypeVar("F", bound=Callable[..., Any])
32
+
33
+ # Tracer name for GatewayDK spans
34
+ TRACER_NAME = "gatewaysdk.tracing"
35
+
36
+
37
+ # =============================================================================
38
+ # Run Context Integration
39
+ # =============================================================================
40
+
41
+
42
+ def _inject_run_context(span: Span) -> None:
43
+ """Inject run_id and session_id from current run/rollout into span attributes.
44
+
45
+ This enables automatic trace linkage when a Gateway Run is active.
46
+ The run_id links traces to the experiment, and session_id links traces
47
+ to the specific episode/rollout within the experiment.
48
+ """
49
+ try:
50
+ # Import here to avoid circular dependency
51
+ from gatewaysdk.run import get_current_rollout, get_current_run
52
+
53
+ current_run = get_current_run()
54
+ current_rollout = get_current_rollout()
55
+
56
+ if current_run is not None:
57
+ # Set run_id for experiment linkage
58
+ if current_run.id:
59
+ span.set_attribute(semconv.RUN_ID, current_run.id)
60
+ if current_run.name:
61
+ span.set_attribute(semconv.RUN_NAME, current_run.name)
62
+
63
+ if current_rollout is not None:
64
+ # Set session_id for episode/rollout grouping
65
+ span.set_attribute(semconv.SESSION_ID, current_rollout.session_id)
66
+ except ImportError:
67
+ # run module not available
68
+ pass
69
+ except Exception as e:
70
+ logger.debug(f"Could not inject run context: {e}")
71
+
72
+
73
+ # =============================================================================
74
+ # Serialization helpers for I/O capture
75
+ # =============================================================================
76
+
77
+
78
+ def _safe_serialize(value: Any) -> Any:
79
+ """Recursively serialize a value to JSON-compatible format."""
80
+ if value is None or isinstance(value, (bool, int, float, str)):
81
+ return value
82
+ if isinstance(value, (list, tuple)):
83
+ return [_safe_serialize(v) for v in value]
84
+ if isinstance(value, dict):
85
+ return {str(k): _safe_serialize(v) for k, v in value.items()}
86
+ # Fallback for complex objects (Pydantic models, dataclasses, etc.)
87
+ if hasattr(value, "model_dump"):
88
+ return _safe_serialize(value.model_dump())
89
+ if hasattr(value, "__dict__"):
90
+ return _safe_serialize(vars(value))
91
+ return str(value)
92
+
93
+
94
+ def _serialize_value(value: Any) -> str:
95
+ """Safely serialize a value to a JSON string for span attributes."""
96
+ if value is None:
97
+ return "null"
98
+ if isinstance(value, str):
99
+ return value
100
+ if isinstance(value, (bool, int, float)):
101
+ return json.dumps(value)
102
+ try:
103
+ return json.dumps(_safe_serialize(value))
104
+ except Exception:
105
+ return str(value)
106
+
107
+
108
+ def _capture_function_input(fn: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any]) -> str:
109
+ """Capture function arguments as a JSON string."""
110
+ try:
111
+ sig = inspect.signature(fn)
112
+ bound = sig.bind(*args, **kwargs)
113
+ bound.apply_defaults()
114
+
115
+ # Filter out 'self' and 'cls' parameters
116
+ input_dict = {k: _safe_serialize(v) for k, v in bound.arguments.items() if k not in ("self", "cls")}
117
+
118
+ return json.dumps(input_dict) if input_dict else "{}"
119
+ except Exception:
120
+ # Fallback: simple representation
121
+ return json.dumps({"args": [str(a) for a in args], "kwargs": {k: str(v) for k, v in kwargs.items()}})
122
+
123
+
124
+ def _get_tracer() -> Tracer:
125
+ """Get the GatewaySDK tracer instance."""
126
+ return otel_trace.get_tracer(TRACER_NAME)
127
+
128
+
129
+ class trace:
130
+ """Create a trace span - works as both a decorator and context manager.
131
+
132
+ As a decorator, automatically captures function inputs and outputs::
133
+
134
+ @tracing.trace
135
+ def my_function(query: str) -> dict:
136
+ return {"result": query.upper()}
137
+
138
+ @tracing.trace(name="custom-name", capture_output=False)
139
+ def another_function(data):
140
+ process(data)
141
+
142
+ As a context manager, allows explicit input/output control::
143
+
144
+ with tracing.trace("my-workflow", input=query) as span:
145
+ result = do_work()
146
+ span.set_attribute(tracing.semconv.TRACE_OUTPUT, result)
147
+
148
+ Args:
149
+ name_or_func: Either the span name (str) or the function to decorate.
150
+ name: Explicit span name (for decorator with custom name).
151
+ input: Input value to capture (context manager mode).
152
+ kind: The span kind (default: INTERNAL).
153
+ attributes: Dictionary of attributes to set on the span.
154
+ capture_input: Auto-capture function input (decorator mode, default: True).
155
+ capture_output: Auto-capture function output (decorator mode, default: True).
156
+ record_exception: If True, exceptions are recorded on the span.
157
+ set_status_on_exception: If True, span status is set to ERROR on exception.
158
+ """
159
+
160
+ def __init__(
161
+ self,
162
+ name_or_func: Optional[Union[str, Callable[..., Any]]] = None,
163
+ *,
164
+ name: Optional[str] = None,
165
+ input: Optional[Any] = None,
166
+ kind: SpanKind = SpanKind.INTERNAL,
167
+ attributes: Optional[dict[str, Any]] = None,
168
+ capture_input: bool = True,
169
+ capture_output: bool = True,
170
+ record_exception: bool = True,
171
+ set_status_on_exception: bool = True,
172
+ ):
173
+ self._name_or_func = name_or_func
174
+ self._explicit_name = name
175
+ self._input = input
176
+ self._kind = kind
177
+ self._attributes = attributes
178
+ self._capture_input = capture_input
179
+ self._capture_output = capture_output
180
+ self._record_exception = record_exception
181
+ self._set_status_on_exception = set_status_on_exception
182
+ self._span: Optional[Span] = None
183
+ self._token: Optional[Any] = None
184
+
185
+ # If called as @trace without parentheses, name_or_func is the function
186
+ if callable(name_or_func):
187
+ self._func = name_or_func
188
+ self._span_name = name or name_or_func.__name__
189
+ else:
190
+ self._func = None
191
+ self._span_name = name_or_func or name or "trace"
192
+
193
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
194
+ """Handle decorator invocation."""
195
+ # If we already have a function, this is the actual call
196
+ if self._func is not None:
197
+ if asyncio.iscoroutinefunction(self._func):
198
+ return self._invoke_decorated_async(self._func, args, kwargs)
199
+ return self._invoke_decorated(self._func, args, kwargs)
200
+
201
+ # If first arg is a callable, we're being used as @trace(...) decorator
202
+ if args and callable(args[0]) and not kwargs:
203
+ func = args[0]
204
+ self._func = func
205
+ self._span_name = self._explicit_name or func.__name__
206
+
207
+ # Return a wrapper that will be called when the function is invoked
208
+ if asyncio.iscoroutinefunction(func):
209
+
210
+ @functools.wraps(func)
211
+ async def async_wrapper(*a: Any, **kw: Any) -> Any:
212
+ return await self._invoke_decorated_async(func, a, kw)
213
+
214
+ return async_wrapper
215
+ else:
216
+
217
+ @functools.wraps(func)
218
+ def sync_wrapper(*a: Any, **kw: Any) -> Any:
219
+ return self._invoke_decorated(func, a, kw)
220
+
221
+ return sync_wrapper
222
+
223
+ raise TypeError("trace() requires a name string or a function")
224
+
225
+ def _invoke_decorated(self, func: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any:
226
+ """Invoke a decorated sync function with tracing."""
227
+ tracer = _get_tracer()
228
+
229
+ with tracer.start_as_current_span(
230
+ name=self._span_name,
231
+ kind=self._kind,
232
+ attributes=self._attributes,
233
+ record_exception=self._record_exception,
234
+ set_status_on_exception=self._set_status_on_exception,
235
+ ) as span:
236
+ # Inject run context (session_id, run_id) if a run is active
237
+ _inject_run_context(span)
238
+
239
+ # Capture input
240
+ if self._capture_input:
241
+ input_val = _capture_function_input(func, args, kwargs)
242
+ span.set_attribute(semconv.OBSERVATION_INPUT, input_val)
243
+
244
+ result = func(*args, **kwargs)
245
+
246
+ # Capture output
247
+ if self._capture_output:
248
+ span.set_attribute(semconv.OBSERVATION_OUTPUT, _serialize_value(result))
249
+
250
+ return result
251
+
252
+ async def _invoke_decorated_async(
253
+ self, func: Callable[..., Any], args: tuple[Any, ...], kwargs: dict[str, Any]
254
+ ) -> Any:
255
+ """Invoke a decorated async function with tracing."""
256
+ tracer = _get_tracer()
257
+
258
+ with tracer.start_as_current_span(
259
+ name=self._span_name,
260
+ kind=self._kind,
261
+ attributes=self._attributes,
262
+ record_exception=self._record_exception,
263
+ set_status_on_exception=self._set_status_on_exception,
264
+ ) as span:
265
+ # Inject run context (session_id, run_id) if a run is active
266
+ _inject_run_context(span)
267
+
268
+ # Capture input
269
+ if self._capture_input:
270
+ input_val = _capture_function_input(func, args, kwargs)
271
+ span.set_attribute(semconv.OBSERVATION_INPUT, input_val)
272
+
273
+ result = await func(*args, **kwargs)
274
+
275
+ # Capture output
276
+ if self._capture_output:
277
+ span.set_attribute(semconv.OBSERVATION_OUTPUT, _serialize_value(result))
278
+
279
+ return result
280
+
281
+ def __enter__(self) -> Span:
282
+ """Context manager entry - start the span."""
283
+ tracer = _get_tracer()
284
+ self._span = tracer.start_span(
285
+ name=self._span_name,
286
+ kind=self._kind,
287
+ attributes=self._attributes,
288
+ record_exception=self._record_exception,
289
+ set_status_on_exception=self._set_status_on_exception,
290
+ )
291
+ # Store the context manager to properly exit later
292
+ self._use_span_cm = otel_trace.use_span(self._span, end_on_exit=False)
293
+ self._use_span_cm.__enter__()
294
+
295
+ # Inject run context (session_id, run_id) if a run is active
296
+ _inject_run_context(self._span)
297
+
298
+ # Set input if provided
299
+ if self._input is not None:
300
+ self._span.set_attribute(semconv.TRACE_INPUT, _serialize_value(self._input))
301
+
302
+ return self._span
303
+
304
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
305
+ """Context manager exit - end the span."""
306
+ try:
307
+ if self._span is not None:
308
+ if exc_val is not None and self._record_exception:
309
+ self._span.record_exception(exc_val)
310
+ if exc_val is not None and self._set_status_on_exception:
311
+ self._span.set_status(Status(StatusCode.ERROR, str(exc_val)))
312
+ self._span.end()
313
+ finally:
314
+ if hasattr(self, "_use_span_cm") and self._use_span_cm is not None:
315
+ self._use_span_cm.__exit__(exc_type, exc_val, exc_tb)
316
+
317
+
318
+ @contextmanager
319
+ def span(
320
+ name: str,
321
+ *,
322
+ input: Optional[Any] = None,
323
+ kind: SpanKind = SpanKind.INTERNAL,
324
+ attributes: Optional[dict[str, Any]] = None,
325
+ record_exception: bool = True,
326
+ set_status_on_exception: bool = True,
327
+ **extra_attributes: Any,
328
+ ) -> Generator[Span, None, None]:
329
+ """Context manager to create a child span.
330
+
331
+ This creates a span that will be a child of the current active span.
332
+ If no active span exists, it becomes a root span.
333
+
334
+ Args:
335
+ name: The name of the span.
336
+ input: Input value to capture (displayed in Gateway UI).
337
+ kind: The span kind (default: INTERNAL).
338
+ attributes: Dictionary of attributes to set on the span.
339
+ record_exception: If True, exceptions are recorded on the span.
340
+ set_status_on_exception: If True, span status is set to ERROR on exception.
341
+ **extra_attributes: Additional attributes as keyword arguments.
342
+
343
+ Yields:
344
+ The OpenTelemetry Span object.
345
+
346
+ Example::
347
+
348
+ import gatewaysdk.tracing as tracing
349
+
350
+ with tracing.trace("my-workflow"):
351
+ with tracing.span("step.load_data", input=dataset_name) as s:
352
+ data = load_data()
353
+ s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(len(data)))
354
+
355
+ with tracing.span("step.process"):
356
+ process(data)
357
+ """
358
+ tracer = _get_tracer()
359
+ all_attributes = {**(attributes or {}), **extra_attributes}
360
+
361
+ with tracer.start_as_current_span(
362
+ name=name,
363
+ kind=kind,
364
+ attributes=all_attributes if all_attributes else None,
365
+ record_exception=record_exception,
366
+ set_status_on_exception=set_status_on_exception,
367
+ ) as otel_span:
368
+ # Set input if provided
369
+ if input is not None:
370
+ otel_span.set_attribute(semconv.OBSERVATION_INPUT, _serialize_value(input))
371
+ try:
372
+ yield otel_span
373
+ except Exception:
374
+ raise
375
+
376
+
377
+ @contextmanager
378
+ def tool(
379
+ name: str,
380
+ *,
381
+ input: Optional[Any] = None,
382
+ tool_name: Optional[str] = None,
383
+ attributes: Optional[dict[str, Any]] = None,
384
+ record_exception: bool = True,
385
+ set_status_on_exception: bool = True,
386
+ **extra_attributes: Any,
387
+ ) -> Generator[Span, None, None]:
388
+ """Context manager to trace a tool execution.
389
+
390
+ This creates a span with TOOL kind and semantic attributes for tool calls.
391
+ Useful for tracing function calls, API calls, or other discrete operations.
392
+
393
+ Args:
394
+ name: The span name (often the function/tool name).
395
+ input: Input value to capture (displayed in Gateway UI).
396
+ tool_name: Explicit tool name attribute (defaults to name).
397
+ attributes: Dictionary of attributes to set on the span.
398
+ record_exception: If True, exceptions are recorded on the span.
399
+ set_status_on_exception: If True, span status is set to ERROR on exception.
400
+ **extra_attributes: Additional attributes as keyword arguments.
401
+
402
+ Yields:
403
+ The OpenTelemetry Span object.
404
+
405
+ Example::
406
+
407
+ import gatewaysdk.tracing as tracing
408
+
409
+ with tracing.tool("search_database", input=query) as s:
410
+ results = db.execute(query)
411
+ s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(len(results)))
412
+ """
413
+ tracer = _get_tracer()
414
+ all_attributes = {
415
+ "tool.name": tool_name or name,
416
+ # Without this the ingestion mapper (which reads
417
+ # gateway.observation.type) files manual tool spans as plain SPANs —
418
+ # breaking anything that selects TOOL observations (replay stubs,
419
+ # tool-failure evals, dashboards).
420
+ semconv.OBSERVATION_TYPE: "tool",
421
+ **(attributes or {}),
422
+ **extra_attributes,
423
+ }
424
+
425
+ # Use CLIENT kind for tool calls (external service calls)
426
+ with tracer.start_as_current_span(
427
+ name=name,
428
+ kind=SpanKind.CLIENT,
429
+ attributes=all_attributes,
430
+ record_exception=record_exception,
431
+ set_status_on_exception=set_status_on_exception,
432
+ ) as otel_span:
433
+ # Set input if provided
434
+ if input is not None:
435
+ otel_span.set_attribute(semconv.OBSERVATION_INPUT, _serialize_value(input))
436
+ try:
437
+ yield otel_span
438
+ except Exception:
439
+ raise
440
+
441
+
442
+ @asynccontextmanager
443
+ async def atrace(
444
+ name: str,
445
+ *,
446
+ input: Optional[Any] = None,
447
+ kind: SpanKind = SpanKind.INTERNAL,
448
+ attributes: Optional[dict[str, Any]] = None,
449
+ record_exception: bool = True,
450
+ set_status_on_exception: bool = True,
451
+ **extra_attributes: Any,
452
+ ) -> AsyncGenerator[Span, None]:
453
+ """Async context manager to create a trace (root span).
454
+
455
+ Async variant of trace() for use in async code.
456
+
457
+ Args:
458
+ name: The name of the trace/span.
459
+ input: Input value to capture (displayed in Gateway UI).
460
+ kind: The span kind (default: INTERNAL).
461
+ attributes: Dictionary of attributes to set on the span.
462
+ record_exception: If True, exceptions are recorded on the span.
463
+ set_status_on_exception: If True, span status is set to ERROR on exception.
464
+ **extra_attributes: Additional attributes as keyword arguments.
465
+
466
+ Yields:
467
+ The OpenTelemetry Span object.
468
+
469
+ Example::
470
+
471
+ import gatewaysdk.tracing as tracing
472
+
473
+ async with tracing.atrace("my-async-workflow", input=query) as span:
474
+ result = await async_operation()
475
+ span.set_attribute(tracing.semconv.TRACE_OUTPUT, result)
476
+ """
477
+ tracer = _get_tracer()
478
+ all_attributes = {**(attributes or {}), **extra_attributes}
479
+
480
+ with tracer.start_as_current_span(
481
+ name=name,
482
+ kind=kind,
483
+ attributes=all_attributes if all_attributes else None,
484
+ record_exception=record_exception,
485
+ set_status_on_exception=set_status_on_exception,
486
+ ) as otel_span:
487
+ # Set input if provided
488
+ if input is not None:
489
+ otel_span.set_attribute(semconv.TRACE_INPUT, _serialize_value(input))
490
+ try:
491
+ yield otel_span
492
+ except Exception:
493
+ raise
494
+
495
+
496
+ @asynccontextmanager
497
+ async def aspan(
498
+ name: str,
499
+ *,
500
+ input: Optional[Any] = None,
501
+ kind: SpanKind = SpanKind.INTERNAL,
502
+ attributes: Optional[dict[str, Any]] = None,
503
+ record_exception: bool = True,
504
+ set_status_on_exception: bool = True,
505
+ **extra_attributes: Any,
506
+ ) -> AsyncGenerator[Span, None]:
507
+ """Async context manager to create a child span.
508
+
509
+ Async variant of span() for use in async code.
510
+
511
+ Args:
512
+ name: The name of the span.
513
+ input: Input value to capture (displayed in Gateway UI).
514
+ kind: The span kind (default: INTERNAL).
515
+ attributes: Dictionary of attributes to set on the span.
516
+ record_exception: If True, exceptions are recorded on the span.
517
+ set_status_on_exception: If True, span status is set to ERROR on exception.
518
+ **extra_attributes: Additional attributes as keyword arguments.
519
+
520
+ Yields:
521
+ The OpenTelemetry Span object.
522
+
523
+ Example::
524
+
525
+ import gatewaysdk.tracing as tracing
526
+
527
+ async with tracing.atrace("workflow", input=query):
528
+ async with tracing.aspan("fetch_data") as s:
529
+ data = await fetch()
530
+ s.set_attribute(tracing.semconv.OBSERVATION_OUTPUT, str(len(data)))
531
+ """
532
+ tracer = _get_tracer()
533
+ all_attributes = {**(attributes or {}), **extra_attributes}
534
+
535
+ with tracer.start_as_current_span(
536
+ name=name,
537
+ kind=kind,
538
+ attributes=all_attributes if all_attributes else None,
539
+ record_exception=record_exception,
540
+ set_status_on_exception=set_status_on_exception,
541
+ ) as otel_span:
542
+ # Set input if provided
543
+ if input is not None:
544
+ otel_span.set_attribute(semconv.OBSERVATION_INPUT, _serialize_value(input))
545
+ try:
546
+ yield otel_span
547
+ except Exception:
548
+ raise
549
+
550
+
551
+ def trace_decorator(
552
+ func: Optional[F] = None,
553
+ *,
554
+ name: Optional[str] = None,
555
+ kind: SpanKind = SpanKind.INTERNAL,
556
+ attributes: Optional[dict[str, Any]] = None,
557
+ record_exception: bool = True,
558
+ set_status_on_exception: bool = True,
559
+ ) -> Union[F, Callable[[F], F]]:
560
+ """Decorator to trace a function execution.
561
+
562
+ Can be used with or without parentheses:
563
+ @trace_decorator
564
+ def my_func(): ...
565
+
566
+ @trace_decorator(name="custom-name")
567
+ def my_func(): ...
568
+
569
+ Works with both sync and async functions.
570
+
571
+ Args:
572
+ func: The function to decorate (when used without parentheses).
573
+ name: Custom span name. Defaults to the function name.
574
+ kind: The span kind (default: INTERNAL).
575
+ attributes: Dictionary of attributes to set on the span.
576
+ record_exception: If True, exceptions are recorded on the span.
577
+ set_status_on_exception: If True, span status is set to ERROR on exception.
578
+
579
+ Returns:
580
+ Decorated function.
581
+
582
+ Example::
583
+
584
+ import gatewaysdk.tracing_claude as tracing
585
+
586
+ @tracing.trace
587
+ def process_data(items):
588
+ return [process(item) for item in items]
589
+
590
+ @tracing.trace(name="custom-operation", attributes={"version": "1.0"})
591
+ async def async_operation():
592
+ return await do_something()
593
+ """
594
+
595
+ def decorator(fn: F) -> F:
596
+ span_name = name or fn.__name__
597
+ span_attributes = attributes or {}
598
+
599
+ if asyncio.iscoroutinefunction(fn):
600
+
601
+ @functools.wraps(fn)
602
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
603
+ tracer = _get_tracer()
604
+ with tracer.start_as_current_span(
605
+ name=span_name,
606
+ kind=kind,
607
+ attributes=span_attributes if span_attributes else None,
608
+ record_exception=record_exception,
609
+ set_status_on_exception=set_status_on_exception,
610
+ ):
611
+ return await fn(*args, **kwargs)
612
+
613
+ return async_wrapper # type: ignore
614
+ else:
615
+
616
+ @functools.wraps(fn)
617
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
618
+ tracer = _get_tracer()
619
+ with tracer.start_as_current_span(
620
+ name=span_name,
621
+ kind=kind,
622
+ attributes=span_attributes if span_attributes else None,
623
+ record_exception=record_exception,
624
+ set_status_on_exception=set_status_on_exception,
625
+ ):
626
+ return fn(*args, **kwargs)
627
+
628
+ return sync_wrapper # type: ignore
629
+
630
+ if func is None:
631
+ # Called with parentheses: @trace_decorator(...)
632
+ return decorator
633
+ else:
634
+ # Called without parentheses: @trace_decorator
635
+ return decorator(func)
636
+
637
+
638
+ def tool_decorator(
639
+ func: Optional[F] = None,
640
+ *,
641
+ name: Optional[str] = None,
642
+ tool_name: Optional[str] = None,
643
+ attributes: Optional[dict[str, Any]] = None,
644
+ record_exception: bool = True,
645
+ set_status_on_exception: bool = True,
646
+ ) -> Union[F, Callable[[F], F]]:
647
+ """Decorator to trace a tool/function execution.
648
+
649
+ Similar to trace_decorator but uses CLIENT span kind and adds tool.name attribute.
650
+
651
+ Args:
652
+ func: The function to decorate (when used without parentheses).
653
+ name: Custom span name. Defaults to the function name.
654
+ tool_name: Tool name attribute. Defaults to span name.
655
+ attributes: Dictionary of attributes to set on the span.
656
+ record_exception: If True, exceptions are recorded on the span.
657
+ set_status_on_exception: If True, span status is set to ERROR on exception.
658
+
659
+ Returns:
660
+ Decorated function.
661
+
662
+ Example::
663
+
664
+ import gatewaysdk.tracing_claude as tracing
665
+
666
+ @tracing.tool
667
+ def search_database(query: str) -> list:
668
+ return db.execute(query)
669
+ """
670
+
671
+ def decorator(fn: F) -> F:
672
+ span_name = name or fn.__name__
673
+ span_attributes = {
674
+ "tool.name": tool_name or span_name,
675
+ **(attributes or {}),
676
+ }
677
+
678
+ if asyncio.iscoroutinefunction(fn):
679
+
680
+ @functools.wraps(fn)
681
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
682
+ tracer = _get_tracer()
683
+ with tracer.start_as_current_span(
684
+ name=span_name,
685
+ kind=SpanKind.CLIENT,
686
+ attributes=span_attributes,
687
+ record_exception=record_exception,
688
+ set_status_on_exception=set_status_on_exception,
689
+ ):
690
+ return await fn(*args, **kwargs)
691
+
692
+ return async_wrapper # type: ignore
693
+ else:
694
+
695
+ @functools.wraps(fn)
696
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
697
+ tracer = _get_tracer()
698
+ with tracer.start_as_current_span(
699
+ name=span_name,
700
+ kind=SpanKind.CLIENT,
701
+ attributes=span_attributes,
702
+ record_exception=record_exception,
703
+ set_status_on_exception=set_status_on_exception,
704
+ ):
705
+ return fn(*args, **kwargs)
706
+
707
+ return sync_wrapper # type: ignore
708
+
709
+ if func is None:
710
+ return decorator
711
+ else:
712
+ return decorator(func)
713
+
714
+
715
+ def record_exception(
716
+ span: Span,
717
+ exception: BaseException,
718
+ *,
719
+ attributes: Optional[dict[str, Any]] = None,
720
+ escaped: bool = False,
721
+ ) -> None:
722
+ """Record an exception on a span.
723
+
724
+ Helper function for recording exceptions with proper attributes.
725
+
726
+ Args:
727
+ span: The span to record the exception on.
728
+ exception: The exception to record.
729
+ attributes: Additional attributes to record with the exception.
730
+ escaped: Whether the exception escaped the span's scope.
731
+
732
+ Example::
733
+
734
+ import gatewaysdk.tracing_claude as tracing
735
+
736
+ with tracing.span("operation") as s:
737
+ try:
738
+ risky_operation()
739
+ except ValueError as e:
740
+ tracing.record_exception(s, e, attributes={"input": "bad"})
741
+ s.set_status(StatusCode.ERROR, str(e))
742
+ # Handle or re-raise
743
+ """
744
+ span.record_exception(exception, attributes=attributes, escaped=escaped)
745
+
746
+
747
+ def set_span_error(
748
+ span: Span,
749
+ message: str,
750
+ *,
751
+ exception: Optional[BaseException] = None,
752
+ ) -> None:
753
+ """Set a span's status to ERROR with a description.
754
+
755
+ Convenience function for marking a span as failed.
756
+
757
+ Args:
758
+ span: The span to mark as error.
759
+ message: Error description.
760
+ exception: Optional exception to record.
761
+
762
+ Example::
763
+
764
+ import gatewaysdk.tracing_claude as tracing
765
+
766
+ with tracing.span("operation") as s:
767
+ result = do_work()
768
+ if not result.success:
769
+ tracing.set_span_error(s, f"Operation failed: {result.error}")
770
+ """
771
+ span.set_status(Status(StatusCode.ERROR, message))
772
+ if exception is not None:
773
+ span.record_exception(exception)
774
+
775
+
776
+ def set_span_ok(span: Span, message: Optional[str] = None) -> None:
777
+ """Set a span's status to OK.
778
+
779
+ Convenience function for marking a span as successful.
780
+
781
+ Args:
782
+ span: The span to mark as OK.
783
+ message: Optional success message.
784
+ """
785
+ span.set_status(Status(StatusCode.OK, message))
786
+
787
+
788
+ def get_current_span() -> Span:
789
+ """Get the currently active span.
790
+
791
+ Returns:
792
+ The current span, or a non-recording span if none is active.
793
+
794
+ Example::
795
+
796
+ import gatewaysdk.tracing_claude as tracing
797
+
798
+ def inner_function():
799
+ span = tracing.get_current_span()
800
+ span.set_attribute("inner_data", "value")
801
+ """
802
+ return otel_trace.get_current_span()
803
+
804
+
805
+ # Convenience aliases for decorator-style usage
806
+ # These allow: @tracing.trace instead of @tracing.trace_decorator
807
+ # The context manager `trace` takes precedence, but when used as decorator
808
+ # it works because the context manager returns a span, not a wrapper