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,150 @@
1
+ """The ``gateway_env`` handler runtime — the module bundle handlers import.
2
+
3
+ Generated (or hand-written) ``mock-tools`` handlers are written against this
4
+ FIXED contract::
5
+
6
+ from gateway_env import tool, db
7
+
8
+ @tool(name="create_refund")
9
+ def handle(order_id, amount):
10
+ order = db.one("SELECT * FROM orders WHERE id = ?", order_id)
11
+ rid = db.insert("refunds", order_id=order_id, amount=amount)
12
+ return {"ok": True, "refund_id": rid}
13
+
14
+ ``gateway_env`` is importable ONLY while a bundle's handler modules are being
15
+ loaded — the loader injects this module into ``sys.modules`` under that name
16
+ for the duration of the load and restores it after (never globally installed).
17
+ ``db`` operations bind to the ACTIVE world's sqlite connection at call time via
18
+ a contextvar, so the same handler object serves every world/branch.
19
+
20
+ Handlers may also be plain ``def <tool_name>(...)`` functions — the loader
21
+ falls back to discovery by function name == served tool name.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import re
27
+ import sqlite3
28
+ from contextvars import ContextVar
29
+ from typing import Any, Callable, Dict, Optional
30
+
31
+ __all__ = ["tool", "db", "store"]
32
+
33
+ #: The active world's sqlite connection. Set by ``World.execute`` around each
34
+ #: handler invocation; ``db`` reads it at call time.
35
+ _active_connection: ContextVar[Optional[sqlite3.Connection]] = ContextVar(
36
+ "gateway_env_active_connection", default=None
37
+ )
38
+
39
+ #: The registry the loader is currently filling. ``@tool`` registers into it
40
+ #: at module-exec time; outside a bundle load the decorator is a no-op tagger.
41
+ _load_registry: ContextVar[Optional[Dict[str, Callable[..., Any]]]] = ContextVar(
42
+ "gateway_env_load_registry", default=None
43
+ )
44
+
45
+ _active_store: ContextVar[Any] = ContextVar("gateway_env_active_store", default=None)
46
+ _strict_registration: ContextVar[bool] = ContextVar("gateway_env_strict_registration", default=False)
47
+
48
+
49
+ class _Store:
50
+ """Entity operations bind to the currently executing schema-backed world."""
51
+
52
+ def __getattr__(self, name):
53
+ if name not in {"get", "list", "insert", "update", "delete", "apply_batch", "lineage"}:
54
+ raise AttributeError(name)
55
+ active = _active_store.get()
56
+ if active is None:
57
+ raise RuntimeError("gateway_env.store requires an active schema-backed world")
58
+ return getattr(active, name)
59
+
60
+
61
+ store = _Store()
62
+
63
+ _IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
64
+
65
+
66
+ def _connection() -> sqlite3.Connection:
67
+ conn = _active_connection.get()
68
+ if conn is None:
69
+ raise RuntimeError(
70
+ "gateway_env.db has no active world — db.* is only usable while a "
71
+ "tool handler executes inside a world (world.execute / with env:)."
72
+ )
73
+ return conn
74
+
75
+
76
+ def _identifier(name: str, what: str) -> str:
77
+ if not _IDENTIFIER_RE.match(name):
78
+ raise ValueError(f"invalid {what} name for db.insert: {name!r}")
79
+ return name
80
+
81
+
82
+ class _Db:
83
+ """Tiny sqlite facade bound to the active world (rows are ``sqlite3.Row``,
84
+ dict-like: ``row["col"]`` and ``dict(row)`` both work)."""
85
+
86
+ def one(self, sql: str, *params: Any) -> Optional[sqlite3.Row]:
87
+ """First row of the query, or ``None``."""
88
+ return _connection().execute(sql, params).fetchone()
89
+
90
+ def all(self, sql: str, *params: Any) -> list[sqlite3.Row]:
91
+ """Every row of the query."""
92
+ return list(_connection().execute(sql, params).fetchall())
93
+
94
+ def insert(self, table: str, **cols: Any) -> int:
95
+ """INSERT one row, returning its rowid. Table/column names are
96
+ validated as identifiers (values are always bound parameters)."""
97
+ if _active_store.get() is not None:
98
+ from .schema import ContractError
99
+
100
+ raise ContractError("raw_write", "Use gateway_env.store.insert for schema-backed mutations")
101
+ if not cols:
102
+ raise ValueError("db.insert needs at least one column")
103
+ table_sql = _identifier(table, "table")
104
+ col_sql = ", ".join(_identifier(col, "column") for col in cols)
105
+ placeholders = ", ".join("?" for _ in cols)
106
+ cursor = _connection().execute(
107
+ f"INSERT INTO {table_sql} ({col_sql}) VALUES ({placeholders})",
108
+ tuple(cols.values()),
109
+ )
110
+ return int(cursor.lastrowid or 0)
111
+
112
+ def execute(self, sql: str, *params: Any) -> int:
113
+ """Run any statement (UPDATE/DELETE/DDL…), returning the affected
114
+ rowcount (-1 for non-DML per sqlite3 semantics)."""
115
+ if _active_store.get() is not None:
116
+ from .schema import ContractError
117
+
118
+ raise ContractError("raw_write", "Use gateway_env.store for schema-backed mutations")
119
+ return _connection().execute(sql, params).rowcount
120
+
121
+
122
+ db = _Db()
123
+
124
+
125
+ def tool(fn: Optional[Callable[..., Any]] = None, *, name: Optional[str] = None):
126
+ """Register a handler for a served tool.
127
+
128
+ Usable bare (``@tool`` — tool name is the function name) or with an
129
+ explicit name (``@tool(name="crm.lookup")`` — required when the tool name
130
+ is not a valid Python identifier). Returns the function unchanged.
131
+ """
132
+
133
+ def register(handler: Callable[..., Any], tool_name: str) -> Callable[..., Any]:
134
+ handler.__gateway_env_tool__ = tool_name # type: ignore[attr-defined]
135
+ registry = _load_registry.get()
136
+ if registry is not None:
137
+ if _strict_registration.get() and tool_name in registry:
138
+ from .schema import ContractError
139
+
140
+ raise ContractError("tool", "Duplicate tool handler registration")
141
+ registry[tool_name] = handler
142
+ return handler
143
+
144
+ if fn is not None and callable(fn):
145
+ return register(fn, fn.__name__)
146
+
147
+ def decorator(handler: Callable[..., Any]) -> Callable[..., Any]:
148
+ return register(handler, name or handler.__name__)
149
+
150
+ return decorator
@@ -0,0 +1,35 @@
1
+ """Offline executable world contracts: compile, validate, and store state."""
2
+
3
+ from .compiler import (
4
+ Contract,
5
+ bundle_mode,
6
+ check_bundle,
7
+ compile_bundle,
8
+ describe_bundle,
9
+ )
10
+ from .connector import capture as capture_connection
11
+ from .connector import ingest as ingest_captures
12
+ from .connector import load_spec as load_connection
13
+ from .scaffold import init_bundle, list_templates
14
+ from .store import IngestConnection, SQLiteStore
15
+ from .api import build_api_bundle
16
+ from .api import serve as serve_api
17
+ from .validation import ContractError
18
+
19
+ __all__ = [
20
+ "Contract",
21
+ "ContractError",
22
+ "IngestConnection",
23
+ "SQLiteStore",
24
+ "build_api_bundle",
25
+ "bundle_mode",
26
+ "capture_connection",
27
+ "check_bundle",
28
+ "compile_bundle",
29
+ "describe_bundle",
30
+ "ingest_captures",
31
+ "init_bundle",
32
+ "list_templates",
33
+ "load_connection",
34
+ "serve_api",
35
+ ]
@@ -0,0 +1,225 @@
1
+ """Lean CLI, dependency-free: python -m gatewaysdk.environment.schema <command> PATH.
2
+
3
+ init | templates | compile | check | describe the world contract
4
+ connector-validate | connector-capture | connector-ingest | conform its vendor connection
5
+ data-show | data-import the rows a local world seeds with
6
+ serve | api-bundle the vendor's API served from the world
7
+ skill the packaged skills, printed or installed
8
+
9
+ Every command is offline and local: it never reads GATEWAY_* keys or reaches a
10
+ host. The platform's sandboxed `run_gateway_cli` runs exactly this module.
11
+ """
12
+
13
+ import argparse
14
+ import json
15
+ from pathlib import Path
16
+
17
+ from . import (
18
+ ContractError,
19
+ build_api_bundle,
20
+ capture_connection,
21
+ check_bundle,
22
+ describe_bundle,
23
+ ingest_captures,
24
+ init_bundle,
25
+ list_templates,
26
+ load_connection,
27
+ serve_api,
28
+ )
29
+ from .conform import conform
30
+ from .data import entity_counts, entity_rows, import_rows, parse_rows, world_kind
31
+ from .skill import install_skill, next_step, packaged_skills, skill_text
32
+
33
+ COMMANDS = (
34
+ "init",
35
+ "templates",
36
+ "compile",
37
+ "check",
38
+ "describe",
39
+ "connector-validate",
40
+ "connector-capture",
41
+ "connector-ingest",
42
+ "conform",
43
+ "data-show",
44
+ "data-import",
45
+ "serve",
46
+ "api-bundle",
47
+ "skill",
48
+ )
49
+
50
+ NO_BUNDLE = ("templates", "skill")
51
+
52
+
53
+ def _pairs(values):
54
+ out = {}
55
+ for item in values or []:
56
+ if "=" not in item:
57
+ raise SystemExit(f"expected name=value, got {item!r}")
58
+ key, value = item.split("=", 1)
59
+ out[key.strip()] = value
60
+ return out
61
+
62
+
63
+ def _installed_connector(value):
64
+ """This entry point is offline; a workspace connector needs the platform CLI."""
65
+ if value.startswith("workspace:"):
66
+ raise argparse.ArgumentTypeError(
67
+ "workspace connectors live on the platform; use "
68
+ "`gateway worlds schema init PATH --connector workspace:<slug>` with GATEWAY_* keys set"
69
+ )
70
+ return value
71
+
72
+
73
+ def _skill(name, *, list_skills, install, force):
74
+ """Mirror of ``gateway worlds skill``: list, print, or ``--install DIR`` a packaged skill."""
75
+ if list_skills or name is None:
76
+ print(json.dumps({"status": "ok", "skills": packaged_skills()}, sort_keys=True))
77
+ return
78
+ if install is None:
79
+ print(skill_text(name), end="")
80
+ return
81
+ report = install_skill(install, name=name, force=force)
82
+ out = {
83
+ "status": "rejected" if report.conflicts else "ok",
84
+ "skill": name,
85
+ "written": report.written,
86
+ "unchanged": report.unchanged,
87
+ "conflicts": report.conflicts,
88
+ "next": next_step(name),
89
+ }
90
+ print(json.dumps(out, sort_keys=True))
91
+ if report.conflicts:
92
+ raise SystemExit(1)
93
+
94
+
95
+ def main(argv=None):
96
+ parser = argparse.ArgumentParser(description="Offline Gateway world schema contracts")
97
+ parser.add_argument("command", choices=COMMANDS)
98
+ parser.add_argument("bundle", nargs="?", help="world directory (every command but templates and skill); skill: the skill name")
99
+ parser.add_argument("rows", nargs="*", help="data-import: rows files ({entity: [rows]} JSON, {entity,row} JSONL, or bare rows)")
100
+ parser.add_argument(
101
+ "--connector",
102
+ default="custom",
103
+ type=_installed_connector,
104
+ choices=list_templates(),
105
+ help="init only: connector template to start from (default: custom)",
106
+ )
107
+ parser.add_argument("--name", default=None, help="init only: environment name and package id")
108
+ parser.add_argument("--op", default=None, help="connector-capture: operation name")
109
+ parser.add_argument("--arg", action="append", help="connector-capture: path argument name=value")
110
+ parser.add_argument("--param", action="append", help="connector-capture: query parameter name=value")
111
+ parser.add_argument("--max-pages", type=int, default=None, help="connector-capture: page limit")
112
+ parser.add_argument("--batch-id", default=None, help="connector-ingest | data-import: batch id")
113
+ parser.add_argument("--openapi", action="append", help="conform: the vendor's OpenAPI document; repeatable")
114
+ parser.add_argument("--limit", type=int, default=None, help="conform: check only the first N operations")
115
+ parser.add_argument("--entity", default=None, help="data-show: print this entity's rows; data-import: the entity bare-row files hold")
116
+ parser.add_argument("--mode", default="append", help="data-import: append (upsert by primary key) | replace (named entities)")
117
+ parser.add_argument("--port", type=int, default=8080, help="serve: port")
118
+ parser.add_argument("--api-key", default=None, help="serve: pin the accepted credential")
119
+ parser.add_argument("--scenario", default=None, help="serve: start in one of the world's scenarios/<name>")
120
+ parser.add_argument("--out", default=None, help="api-bundle: empty output directory; conform: write the full report as JSON here")
121
+ parser.add_argument("--list", action="store_true", help="skill: list the packaged skills and exit")
122
+ parser.add_argument("--install", default=None, help="skill: repository to install the skill into, under its .claude/")
123
+ parser.add_argument("--force", action="store_true", help="skill --install: overwrite files whose content differs")
124
+ args = parser.parse_args(argv)
125
+ if args.command == "skill":
126
+ if args.rows:
127
+ parser.error("skill takes at most one positional argument")
128
+ elif args.command in NO_BUNDLE:
129
+ if args.bundle or args.rows:
130
+ parser.error(f"{args.command} takes no positional argument")
131
+ elif not args.bundle:
132
+ parser.error(f"{args.command} needs a world directory")
133
+ elif args.rows and args.command != "data-import":
134
+ parser.error(f"{args.command} takes one positional argument")
135
+ try:
136
+ if args.command == "templates":
137
+ print(json.dumps({"status": "ok", "templates": list_templates()}, sort_keys=True))
138
+ return
139
+ if args.command == "skill":
140
+ _skill(args.bundle, list_skills=args.list, install=args.install, force=args.force)
141
+ return
142
+ if args.command == "describe":
143
+ print(describe_bundle(args.bundle), end="")
144
+ return
145
+ if args.command == "init":
146
+ contract = init_bundle(args.bundle, connector=args.connector, name=args.name)
147
+ elif args.command == "compile":
148
+ from .compiler import compile_world
149
+
150
+ contract, snapshots = compile_world(args.bundle)
151
+ print(json.dumps({"status": "ok", "domain": contract.target, "snapshots": snapshots}, sort_keys=True))
152
+ return
153
+ elif args.command == "check":
154
+ contract = check_bundle(args.bundle)
155
+ elif args.command == "connector-validate":
156
+ spec = load_connection(args.bundle)
157
+ print(
158
+ json.dumps({"status": "ok", "slug": spec.slug, "operations": sorted(spec.operations)}, sort_keys=True)
159
+ )
160
+ return
161
+ elif args.command == "connector-capture":
162
+ if not args.op:
163
+ raise SystemExit("connector-capture needs --op")
164
+ files = capture_connection(
165
+ args.bundle, args.op, _pairs(args.arg), _pairs(args.param), max_pages=args.max_pages
166
+ )
167
+ print(json.dumps({"status": "ok", "files": [str(f) for f in files]}, sort_keys=True))
168
+ return
169
+ elif args.command == "connector-ingest":
170
+ print(json.dumps({"status": "ok", **ingest_captures(args.bundle, batch_id=args.batch_id)}, sort_keys=True))
171
+ return
172
+ elif args.command == "conform":
173
+ if not args.openapi:
174
+ raise SystemExit("conform needs at least one --openapi document")
175
+ report = conform(args.bundle, args.openapi, max_operations=args.limit)
176
+ if args.out:
177
+ Path(args.out).write_text(json.dumps(report.to_json(), indent=2, sort_keys=True) + "\n")
178
+ print(json.dumps({"status": "ok", **report.to_json()}, sort_keys=True))
179
+ summary = report.summary
180
+ if summary["status_mismatch"] or summary["schema_violations"]:
181
+ raise SystemExit(1)
182
+ return
183
+ elif args.command == "data-show":
184
+ out = {"status": "ok", "kind": world_kind(args.bundle)}
185
+ if args.entity is None:
186
+ out["entity_counts"] = entity_counts(args.bundle)
187
+ else:
188
+ out["entity"] = args.entity
189
+ out["rows"] = entity_rows(args.bundle, args.entity)
190
+ print(json.dumps(out, sort_keys=True))
191
+ return
192
+ elif args.command == "data-import":
193
+ if not args.rows:
194
+ raise SystemExit("data-import needs at least one rows file")
195
+ parsed = parse_rows(args.rows, entity=args.entity)
196
+ result = import_rows(args.bundle, parsed, mode=args.mode, batch_id=args.batch_id)
197
+ print(json.dumps({"status": "ok", **result}, sort_keys=True))
198
+ return
199
+ elif args.command == "serve":
200
+ server = serve_api(args.bundle, port=args.port, api_key=args.api_key, scenario=args.scenario)
201
+ try:
202
+ server.serve_forever()
203
+ finally:
204
+ server.server_close()
205
+ server.world_state.close()
206
+ return
207
+ elif args.command == "api-bundle":
208
+ if not args.out:
209
+ raise SystemExit("api-bundle needs --out")
210
+ print(json.dumps({"status": "ok", "bundle": str(build_api_bundle(args.bundle, args.out))}, sort_keys=True))
211
+ return
212
+ print(json.dumps({"status": "ok", "domain": contract.target}, sort_keys=True))
213
+ except ContractError as error:
214
+ print(json.dumps({"status": "rejected", "error": error.detail}, sort_keys=True))
215
+ raise SystemExit(1)
216
+ except KeyError as error:
217
+ print(json.dumps({"status": "rejected", "error": {"message": str(error.args[0])}}, sort_keys=True))
218
+ raise SystemExit(1)
219
+ except (OSError, ValueError) as error:
220
+ print(json.dumps({"status": "rejected", "error": {"message": str(error)}}, sort_keys=True))
221
+ raise SystemExit(1)
222
+
223
+
224
+ if __name__ == "__main__":
225
+ main()
@@ -0,0 +1,116 @@
1
+ """Slack capability authoring and version-bound coverage reports.
2
+
3
+ Authoring has exactly two shallow defaults maps. Published entries are expanded,
4
+ so consumers never implement inheritance or infer collection from vendor URLs.
5
+ """
6
+
7
+ from copy import deepcopy
8
+ import hashlib
9
+ from pathlib import Path
10
+
11
+ from .validation import encoded, fail, read_json
12
+
13
+ TEMPLATE = Path(__file__).with_name("connectors") / "slack"
14
+
15
+
16
+ def expand_capabilities(document: dict) -> dict:
17
+ """Expand v2 author metadata to self-contained v1 entries; overrides replace.
18
+
19
+ A list/dictionary override replaces the entire default value. There is no
20
+ recursive merge, multi-level inheritance, or mutation of the authored input.
21
+ Already expanded v1 documents remain usable.
22
+ """
23
+ result = deepcopy(document)
24
+ if result.get("format") == "gateway-slack-capabilities/1":
25
+ return result
26
+ if result.get("format") != "gateway-slack-capabilities/2":
27
+ fail("slack_capabilities", "Unsupported capability format", "/capabilities/format")
28
+ defaults = result.pop("defaults", {})
29
+ if not isinstance(defaults, dict) or set(defaults) - {"entities", "operations"}:
30
+ fail("slack_capabilities", "Expected entity and operation defaults", "/capabilities/defaults")
31
+ for kind in ("entities", "operations"):
32
+ common = defaults.get(kind, {})
33
+ entries = result.get(kind)
34
+ if not isinstance(common, dict) or not isinstance(entries, dict):
35
+ fail("slack_capabilities", "Expected named capability objects", f"/capabilities/{kind}")
36
+ for name, entry in entries.items():
37
+ if not isinstance(entry, dict):
38
+ fail("slack_capabilities", "Expected a capability object", f"/capabilities/{kind}/{name}")
39
+ entries[name] = {**deepcopy(common), **entry}
40
+ result["format"] = "gateway-slack-capabilities/1"
41
+ return result
42
+
43
+
44
+ def load_capabilities() -> dict:
45
+ return expand_capabilities(read_json(TEMPLATE / "capabilities.json"))
46
+
47
+
48
+ def slack_template_digest() -> str:
49
+ """Match the platform's path-NUL-bytes-NUL hash over shipped Slack files."""
50
+ root = TEMPLATE
51
+ digest = hashlib.sha256()
52
+ for path in sorted(root.rglob("*"), key=lambda p: p.relative_to(root).as_posix()):
53
+ if not path.is_file() or path.is_symlink() or "__pycache__" in path.parts:
54
+ continue
55
+ digest.update(path.relative_to(root).as_posix().encode("utf-8"))
56
+ digest.update(b"\0")
57
+ digest.update(path.read_bytes())
58
+ digest.update(b"\0")
59
+ return digest.hexdigest()
60
+
61
+
62
+ def fidelity_report(contract, evidence, batch, diagnostics=None, *, mapping):
63
+ synthetic = evidence.get("synthetic") is True
64
+ capabilities = load_capabilities()
65
+ counts = {entity: 0 for entity in contract.entities}
66
+ for mutation in batch["mutations"]:
67
+ counts[mutation["entity"]] += 1
68
+ return {
69
+ "format": "gateway-slack-fidelity/1",
70
+ "shape": "base",
71
+ "label": "synthetic" if synthetic else "subset",
72
+ "source_hash": hashlib.sha256(encoded(evidence)).hexdigest(),
73
+ "template_digest": slack_template_digest(),
74
+ "contract_target": contract.target,
75
+ "package": contract.lock["package"],
76
+ "lock_digest": hashlib.sha256(encoded(contract.lock)).hexdigest(),
77
+ "mapping": mapping,
78
+ "coverage": evidence.get("coverage", {"complete": False}),
79
+ "capture_policy": {
80
+ "methods": capabilities["capture_methods"],
81
+ "description": (
82
+ "platform_capture describes the hosted connector pipeline, independent of observed counts. "
83
+ "collected means a directly requested entity; derived means an association or embedded object "
84
+ "from projected responses. Both remain bounded by selected scope and available fields. "
85
+ "capture_source is a vendor source reference, not proof the connector calls that method. "
86
+ "observed_mutations counts this import batch; synthetic_fixture_mutations identifies its invented rows."
87
+ ),
88
+ },
89
+ "checks": {
90
+ "schema_artifacts": "passed",
91
+ "initial_state": "passed",
92
+ "reference_closure": "passed",
93
+ "live_comparison": "skipped",
94
+ },
95
+ "entities": {
96
+ entity: {
97
+ **capabilities["entities"][entity],
98
+ "observed_mutations": counts[entity],
99
+ "synthetic_fixture_mutations": counts[entity] if synthetic else 0,
100
+ }
101
+ for entity in sorted(contract.entities)
102
+ },
103
+ "live_replay": {
104
+ "status": "skipped",
105
+ "score": None,
106
+ "reason": "No live response comparison performed by this offline mapper.",
107
+ },
108
+ "drift": {
109
+ "status": "reported",
110
+ "unknown_fields": sorted(
111
+ {name for observation in evidence["observations"] for name in observation.get("unknownFields", [])}
112
+ ),
113
+ "unmapped_fields": sorted((diagnostics or {}).get("unmapped_fields", [])),
114
+ },
115
+ "limitations": capabilities["limitations"],
116
+ }