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,428 @@
1
+ """Conformance: does the served world answer the way the vendor's OpenAPI says it does?
2
+
3
+ A world is 1:1 when every declared operation, called the way the vendor's client
4
+ calls it, comes back with the status the vendor documents and a body the vendor's
5
+ response schema accepts. This runs the world in-process, drives each operation
6
+ with arguments taken from the world's own seeded rows (so lookups hit data), and
7
+ validates each answer against the OpenAPI document TRM or the vendor supplied.
8
+
9
+ gateway worlds connector conform ./torchlight-world --openapi briefs/torchlight-openapi.yaml
10
+
11
+ The validator here is deliberately lenient and standalone: vendor documents use
12
+ the whole of OpenAPI 3.1 (``nullable``, ``readOnly``, ``example`` siblings,
13
+ ``discriminator``), which the world contract's strict validator refuses on
14
+ purpose. What is checked: types (with ``null``), ``required``, ``properties``
15
+ (unknown members allowed unless ``additionalProperties: false``), ``items``,
16
+ ``enum``, ``const``, ``allOf``/``anyOf``/``oneOf`` and ``$ref`` into the document.
17
+ Formats are not checked — a mock that answers a UUID-shaped string where the
18
+ vendor answers a UUID is not the failure this tool exists to find.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import base64
24
+ import json
25
+ import threading
26
+ import urllib.error
27
+ import urllib.parse
28
+ import urllib.request
29
+ from dataclasses import dataclass, field
30
+ from pathlib import Path
31
+ from typing import Any
32
+
33
+ from .api import WorldState, load_api_settings, serve
34
+ from .connector import Operation, load_spec
35
+ from .validation import fail
36
+
37
+ PIN = "conform"
38
+
39
+
40
+ # ---------------------------------------------------------------- the document
41
+
42
+
43
+ def load_openapi(path: str | Path) -> dict:
44
+ text = Path(path).read_text(encoding="utf-8")
45
+ if str(path).endswith((".yaml", ".yml")):
46
+ try:
47
+ import yaml # optional at runtime; the SDK depends on it, the vendored server does not
48
+ except ImportError: # pragma: no cover
49
+ fail("conform", "Reading a YAML document needs PyYAML; convert it to JSON", "/conform/openapi")
50
+ document = yaml.safe_load(text)
51
+ else:
52
+ document = json.loads(text)
53
+ if not isinstance(document, dict) or "paths" not in document:
54
+ fail("conform", f"{path} is not an OpenAPI document (no paths)", "/conform/openapi")
55
+ return document
56
+
57
+
58
+ def server_prefixes(document: dict) -> list[str]:
59
+ """The path part of each server URL, longest first, so a world whose paths carry
60
+ the vendor's prefix (``/investigations-v2/breach/...``) still lines up."""
61
+ prefixes: list[str] = []
62
+ for server in document.get("servers") or []:
63
+ url = server.get("url", "") if isinstance(server, dict) else ""
64
+ for name, variable in ((server.get("variables") or {}) if isinstance(server, dict) else {}).items():
65
+ url = url.replace("{" + name + "}", str(variable.get("default", "")))
66
+ path = urllib.parse.urlsplit(url).path.rstrip("/") if "://" in url else url.rstrip("/")
67
+ if path and path not in prefixes:
68
+ prefixes.append(path)
69
+ return sorted(prefixes, key=len, reverse=True)
70
+
71
+
72
+ def _canonical(path: str) -> str:
73
+ """Placeholder names differ between the world and the document; shapes must not."""
74
+ out, depth = [], 0
75
+ for char in path:
76
+ if char == "{":
77
+ depth += 1
78
+ out.append("{}")
79
+ elif char == "}":
80
+ depth -= 1
81
+ elif depth == 0:
82
+ out.append(char)
83
+ return "".join(out)
84
+
85
+
86
+ def find_operation(document: dict, prefixes: list[str], operation: Operation) -> tuple[str, dict] | None:
87
+ """The document's path item + method for a world operation, prefix-tolerant."""
88
+ candidates = [operation.path] + [operation.path[len(p) :] for p in prefixes if operation.path.startswith(p + "/")]
89
+ wanted = {_canonical(c) for c in candidates}
90
+ for path, item in (document.get("paths") or {}).items():
91
+ if _canonical(path) in wanted and isinstance(item, dict) and operation.method.lower() in item:
92
+ return path, item[operation.method.lower()]
93
+ return None
94
+
95
+
96
+ # ---------------------------------------------------------------- lenient validation
97
+
98
+
99
+ class Checker:
100
+ def __init__(self, document: dict):
101
+ self.document = document
102
+
103
+ def deref(self, schema: Any, seen: tuple[str, ...] = ()) -> dict:
104
+ while isinstance(schema, dict) and "$ref" in schema:
105
+ ref = schema["$ref"]
106
+ if ref in seen or not ref.startswith("#/"):
107
+ return {}
108
+ seen = seen + (ref,)
109
+ node: Any = self.document
110
+ for part in ref[2:].split("/"):
111
+ part = part.replace("~1", "/").replace("~0", "~")
112
+ node = node.get(part) if isinstance(node, dict) else None
113
+ if node is None:
114
+ return {}
115
+ siblings = {k: v for k, v in schema.items() if k != "$ref"}
116
+ schema = {**node, **siblings} if isinstance(node, dict) else {}
117
+ return schema if isinstance(schema, dict) else {}
118
+
119
+ def check(self, schema: Any, value: Any, path: str = "$") -> list[str]:
120
+ schema = self.deref(schema)
121
+ if not schema:
122
+ return []
123
+ problems: list[str] = []
124
+ types = schema.get("type")
125
+ types = [types] if isinstance(types, str) else list(types or [])
126
+ if schema.get("nullable") and "null" not in types:
127
+ types.append("null")
128
+ actual = {
129
+ type(None): "null",
130
+ bool: "boolean",
131
+ str: "string",
132
+ dict: "object",
133
+ list: "array",
134
+ int: "integer",
135
+ float: "number",
136
+ }.get(type(value), "unknown")
137
+ if types and not (
138
+ actual in types
139
+ or (actual == "integer" and "number" in types)
140
+ or (actual == "number" and "integer" in types and float(value).is_integer())
141
+ ):
142
+ return [f"{path}: expected {' | '.join(types)}, got {actual}"]
143
+ if value is None:
144
+ return problems
145
+ if "enum" in schema and value not in schema["enum"]:
146
+ problems.append(f"{path}: {value!r} is not one of the enum")
147
+ if "const" in schema and value != schema["const"]:
148
+ problems.append(f"{path}: differs from const {schema['const']!r}")
149
+ for keyword in ("allOf", "anyOf", "oneOf"):
150
+ branches = schema.get(keyword) or []
151
+ if not branches:
152
+ continue
153
+ results = [self.check(branch, value, path) for branch in branches]
154
+ passing = sum(1 for r in results if not r)
155
+ if keyword == "allOf" and passing != len(branches):
156
+ problems.extend(p for r in results for p in r)
157
+ elif keyword == "anyOf" and passing == 0:
158
+ problems.append(f"{path}: matches no anyOf branch ({'; '.join(results[0][:2])})")
159
+ elif keyword == "oneOf" and passing != 1:
160
+ problems.append(f"{path}: matches {passing} oneOf branches, not exactly one")
161
+ if isinstance(value, dict):
162
+ properties = schema.get("properties") or {}
163
+ for name in schema.get("required") or []:
164
+ if name not in value:
165
+ problems.append(f"{path}.{name}: required by the vendor, missing")
166
+ for name, member in value.items():
167
+ if name in properties:
168
+ problems.extend(self.check(properties[name], member, f"{path}.{name}"))
169
+ elif schema.get("additionalProperties") is False:
170
+ problems.append(f"{path}.{name}: not a property the vendor documents")
171
+ elif isinstance(schema.get("additionalProperties"), dict):
172
+ problems.extend(self.check(schema["additionalProperties"], member, f"{path}.{name}"))
173
+ if isinstance(value, list) and isinstance(schema.get("items"), dict):
174
+ for index, item in enumerate(value[:50]):
175
+ problems.extend(self.check(schema["items"], item, f"{path}[{index}]"))
176
+ return problems
177
+
178
+ def example(self, schema: Any, depth: int = 0) -> Any:
179
+ """A body the vendor's request schema accepts, from its examples or its shape."""
180
+ schema = self.deref(schema)
181
+ for key in ("example", "default"):
182
+ if key in schema:
183
+ return schema[key]
184
+ if isinstance(schema.get("examples"), list) and schema["examples"]:
185
+ return schema["examples"][0]
186
+ if "enum" in schema and schema["enum"]:
187
+ return schema["enum"][0]
188
+ for keyword in ("allOf", "anyOf", "oneOf"):
189
+ if schema.get(keyword):
190
+ merged: dict = {}
191
+ for branch in schema[keyword] if keyword == "allOf" else schema[keyword][:1]:
192
+ value = self.example(branch, depth + 1)
193
+ if isinstance(value, dict):
194
+ merged.update(value)
195
+ else:
196
+ return value
197
+ return merged
198
+ types = schema.get("type")
199
+ kind = types if isinstance(types, str) else next((t for t in (types or []) if t != "null"), None)
200
+ if kind == "object" or (kind is None and "properties" in schema):
201
+ if depth > 6:
202
+ return {}
203
+ return {
204
+ name: self.example(prop, depth + 1)
205
+ for name, prop in (schema.get("properties") or {}).items()
206
+ if name in (schema.get("required") or [])
207
+ }
208
+ if kind == "array":
209
+ return (
210
+ [self.example(schema["items"], depth + 1)]
211
+ if isinstance(schema.get("items"), dict) and depth < 6
212
+ else []
213
+ )
214
+ if kind == "integer":
215
+ return int(schema.get("minimum", 1))
216
+ if kind == "number":
217
+ return float(schema.get("minimum", 1))
218
+ if kind == "boolean":
219
+ return True
220
+ if kind == "string":
221
+ fmt = schema.get("format")
222
+ if fmt == "date-time":
223
+ return "2026-01-01T00:00:00Z"
224
+ if fmt == "date":
225
+ return "2026-01-01"
226
+ if fmt == "uuid":
227
+ return "00000000-0000-4000-8000-000000000001"
228
+ if fmt == "email":
229
+ return "sample@example.invalid"
230
+ return "sample"
231
+ return None
232
+
233
+
234
+ # ---------------------------------------------------------------- the run
235
+
236
+
237
+ @dataclass
238
+ class Outcome:
239
+ operation: str
240
+ method: str
241
+ path: str
242
+ documented: bool
243
+ status: int | None = None
244
+ expected: list[str] = field(default_factory=list)
245
+ schema: str = "unchecked" # ok | violations | no-schema | unchecked
246
+ problems: list[str] = field(default_factory=list)
247
+ request: dict = field(default_factory=dict)
248
+
249
+ @property
250
+ def ok(self) -> bool:
251
+ return (
252
+ self.documented
253
+ and self.status is not None
254
+ and str(self.status) in self.expected
255
+ and self.schema in ("ok", "no-schema")
256
+ )
257
+
258
+
259
+ @dataclass
260
+ class Report:
261
+ world: str
262
+ outcomes: list[Outcome]
263
+
264
+ @property
265
+ def summary(self) -> dict:
266
+ checked = [o for o in self.outcomes if o.documented]
267
+ return {
268
+ "operations": len(self.outcomes),
269
+ "documented": len(checked),
270
+ "conforming": sum(1 for o in checked if o.ok),
271
+ "status_mismatch": sum(1 for o in checked if o.status is not None and str(o.status) not in o.expected),
272
+ "schema_violations": sum(1 for o in checked if o.schema == "violations"),
273
+ "undocumented": sum(1 for o in self.outcomes if not o.documented),
274
+ }
275
+
276
+ def to_json(self) -> dict:
277
+ return {"world": self.world, "summary": self.summary, "operations": [o.__dict__ for o in self.outcomes]}
278
+
279
+
280
+ def _credentials(base: str, spec, settings) -> dict[str, str]:
281
+ """Headers that get the conformance run through the world's own auth, using the pin."""
282
+ if spec.scheme == "none":
283
+ return {}
284
+ if spec.scheme == "header":
285
+ return {spec.auth_name or "": PIN}
286
+ if spec.scheme == "bearer":
287
+ return {"Authorization": f"Bearer {PIN}"}
288
+ if spec.scheme == "basic":
289
+ return {"Authorization": "Basic " + base64.b64encode(PIN.encode()).decode()}
290
+ if spec.scheme == "query":
291
+ return {}
292
+ form = urllib.parse.urlencode(
293
+ {"grant_type": "client_credentials", "client_id": "conform", "client_secret": PIN}
294
+ ).encode()
295
+ prefix = urllib.parse.urlsplit(spec.base_url).path.rstrip("/")
296
+ request = urllib.request.Request(base + prefix + (settings.token_path or "/oauth/token"), data=form, method="POST")
297
+ with urllib.request.urlopen(request, timeout=10) as reply:
298
+ return {"Authorization": "Bearer " + json.loads(reply.read())["access_token"]}
299
+
300
+
301
+ def _hints(spec, settings) -> dict[str, tuple[str, str]]:
302
+ """Where a placeholder's values live, learned from every operation that filters on it:
303
+ ``{recordId}`` on a handler route resolves through the read route that maps it to ``id``."""
304
+ hints: dict[str, tuple[str, str]] = {}
305
+ for operation in spec.operations.values():
306
+ if not operation.entity:
307
+ continue
308
+ for arg, path in settings.for_operation(operation.name).filter.items():
309
+ hints.setdefault(arg, (operation.entity, path))
310
+ return hints
311
+
312
+
313
+ def _first_value(rows: list[dict], path: str) -> Any:
314
+ for row in rows:
315
+ found: Any = row
316
+ for part in path.split("."):
317
+ found = found.get(part) if isinstance(found, dict) else None
318
+ if found is not None and not isinstance(found, (dict, list)):
319
+ return found
320
+ return None
321
+
322
+
323
+ def _sample_args(
324
+ operation: Operation, spec, settings, state: WorldState, checker: Checker, documented: dict | None
325
+ ) -> tuple[dict[str, str], dict[str, str]]:
326
+ """Path arguments from the world's own rows — the operation's declared ``sample``
327
+ first (a value a validating handler accepts), then this operation's filter, then any
328
+ operation's filter on the same placeholder, then the entity's primary key — else the
329
+ document's examples. The point is to hit data, not to probe 404s."""
330
+ op = settings.for_operation(operation.name)
331
+ hints = _hints(spec, settings)
332
+ args: dict[str, str] = {}
333
+ params: dict[str, str] = {}
334
+ documented_params = {p.get("name"): p for p in (documented or {}).get("parameters", []) if isinstance(p, dict)}
335
+ for name in operation.params:
336
+ if name in op.sample:
337
+ params[name] = op.sample[name]
338
+ for name in operation.placeholders:
339
+ value = op.sample.get(name)
340
+ if value is None and name in op.filter and operation.entity:
341
+ value = _first_value(state.rows(operation.entity), op.filter[name])
342
+ if value is None and name in hints:
343
+ entity, path = hints[name]
344
+ value = _first_value(state.rows(entity), path)
345
+ if value is None and operation.entity:
346
+ key = state.contract.entities[operation.entity]["primary_key"]
347
+ if len(key) == 1:
348
+ value = _first_value(state.rows(operation.entity), key[0])
349
+ if value is None and name in documented_params:
350
+ value = checker.example(documented_params[name].get("schema") or {})
351
+ args[name] = str(value if value is not None else "1")
352
+ return args, params
353
+
354
+
355
+ def conform(world: str | Path, openapi: list[str | Path], *, max_operations: int | None = None) -> Report:
356
+ root = Path(world)
357
+ spec = load_spec(root)
358
+ settings = load_api_settings(root, spec)
359
+ documents = [load_openapi(p) for p in openapi]
360
+ if not documents:
361
+ fail("conform", "Give at least one --openapi document to conform against", "/conform/openapi")
362
+ server = serve(root, port=0, host="127.0.0.1", api_key=PIN)
363
+ thread = threading.Thread(target=server.serve_forever, daemon=True)
364
+ thread.start()
365
+ base = f"http://127.0.0.1:{server.server_port}"
366
+ prefix = urllib.parse.urlsplit(spec.base_url).path.rstrip("/")
367
+ state: WorldState = server.world_state # type: ignore[attr-defined]
368
+ outcomes: list[Outcome] = []
369
+ try:
370
+ headers = _credentials(base, spec, settings)
371
+ for operation in list(spec.operations.values())[:max_operations]:
372
+ located = None
373
+ checker = None
374
+ for document in documents:
375
+ found = find_operation(document, server_prefixes(document), operation)
376
+ if found:
377
+ located, checker = found, Checker(document)
378
+ break
379
+ outcome = Outcome(operation.name, operation.method, operation.path, documented=located is not None)
380
+ if located is None or checker is None:
381
+ outcomes.append(outcome)
382
+ continue
383
+ _, documented = located
384
+ responses = documented.get("responses") or {}
385
+ outcome.expected = [code for code in responses if code.startswith("2")] or ["200"]
386
+ args, params = _sample_args(operation, spec, settings, state, checker, documented)
387
+ if spec.scheme == "query":
388
+ params[spec.auth_name or ""] = PIN
389
+ path = operation.path
390
+ for name, value in args.items():
391
+ path = path.replace("{" + name + "}", urllib.parse.quote(value, safe=""))
392
+ url = base + prefix + path + (f"?{urllib.parse.urlencode(params)}" if params else "")
393
+ body = None
394
+ content = ((documented.get("requestBody") or {}).get("content") or {}).get("application/json") or {}
395
+ if operation.method in ("POST", "PUT", "PATCH"):
396
+ body = content.get("example") or checker.example(content.get("schema") or {}) or {}
397
+ outcome.request = {"url": prefix + path, "args": args, **({"body": body} if body is not None else {})}
398
+ data = json.dumps(body).encode() if body is not None else None
399
+ request = urllib.request.Request(
400
+ url,
401
+ method=operation.method,
402
+ data=data,
403
+ headers={**headers, **({"Content-Type": "application/json"} if data else {})},
404
+ )
405
+ try:
406
+ with urllib.request.urlopen(request, timeout=15) as reply:
407
+ status, raw = reply.status, reply.read()
408
+ except urllib.error.HTTPError as error:
409
+ status, raw = error.code, error.read()
410
+ outcome.status = status
411
+ answer = responses.get(str(status)) or responses.get("default") or {}
412
+ schema = ((answer.get("content") or {}).get("application/json") or {}).get("schema")
413
+ if schema is None:
414
+ outcome.schema = "no-schema"
415
+ else:
416
+ try:
417
+ value = json.loads(raw) if raw else None
418
+ except json.JSONDecodeError:
419
+ value = None
420
+ outcome.problems.append("$: body is not JSON")
421
+ outcome.problems.extend(checker.check(schema, value))
422
+ outcome.schema = "violations" if outcome.problems else "ok"
423
+ outcomes.append(outcome)
424
+ finally:
425
+ server.shutdown()
426
+ server.server_close()
427
+ state.close()
428
+ return Report(str(root), outcomes)