provekit 0.7.0__tar.gz → 0.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. {provekit-0.7.0 → provekit-0.7.1}/PKG-INFO +1 -1
  2. {provekit-0.7.0 → provekit-0.7.1}/provekit/eval.py +21 -3
  3. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/calibration.py +5 -4
  4. {provekit-0.7.0 → provekit-0.7.1}/provekit/trace.py +38 -7
  5. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/PKG-INFO +1 -1
  6. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/SOURCES.txt +1 -0
  7. {provekit-0.7.0 → provekit-0.7.1}/pyproject.toml +1 -1
  8. provekit-0.7.1/tests/test_self_trace.py +86 -0
  9. {provekit-0.7.0 → provekit-0.7.1}/README.md +0 -0
  10. {provekit-0.7.0 → provekit-0.7.1}/provekit/__init__.py +0 -0
  11. {provekit-0.7.0 → provekit-0.7.1}/provekit/auto.py +0 -0
  12. {provekit-0.7.0 → provekit-0.7.1}/provekit/buffer.py +0 -0
  13. {provekit-0.7.0 → provekit-0.7.1}/provekit/cli.py +0 -0
  14. {provekit-0.7.0 → provekit-0.7.1}/provekit/config.py +0 -0
  15. {provekit-0.7.0 → provekit-0.7.1}/provekit/conformance.py +0 -0
  16. {provekit-0.7.0 → provekit-0.7.1}/provekit/database.py +0 -0
  17. {provekit-0.7.0 → provekit-0.7.1}/provekit/demo.py +0 -0
  18. {provekit-0.7.0 → provekit-0.7.1}/provekit/doctor.py +0 -0
  19. {provekit-0.7.0 → provekit-0.7.1}/provekit/grpc_ingest.py +0 -0
  20. {provekit-0.7.0 → provekit-0.7.1}/provekit/main.py +0 -0
  21. {provekit-0.7.0 → provekit-0.7.1}/provekit/mcp.py +0 -0
  22. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/env.py +0 -0
  23. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/script.py.mako +0 -0
  24. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/9d2c06bfa4e6_baseline.py +0 -0
  25. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/a1b2c3d4e5f6_feedback_sessions.py +0 -0
  26. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/a2b3c4d5e6f7_usage_records.py +0 -0
  27. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/a3b4c5d6e7f8_metric_rollups.py +0 -0
  28. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/a7b8c9d0e1f2_replay_webhook_prompts.py +0 -0
  29. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/a9b0c1d2e3f4_digests.py +0 -0
  30. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b0c1d2e3f4a5_automation_rules.py +0 -0
  31. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b2c3d4e5f6a7_datasets.py +0 -0
  32. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b3c4d5e6f7a8_export_schedules.py +0 -0
  33. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b4c5d6e7f8a9_retention_events.py +0 -0
  34. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b7c8d9e0f1a2_flow_studio.py +0 -0
  35. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/b8c9d0e1f2a3_span_notes.py +0 -0
  36. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c1d2e3f4a5b6_prompts_and_turns.py +0 -0
  37. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c3d4e5f6a7b8_experiments.py +0 -0
  38. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c4d5e6f7a8b9_custom_scorers.py +0 -0
  39. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c5d6e7f8a9b0_search_text.py +0 -0
  40. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c8d9e0f1a2b3_dataset_snapshots.py +0 -0
  41. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/c9d0e1f2a3b4_idempotent_ingest.py +0 -0
  42. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/d0e1f2a3b4c5_alert_webhook.py +0 -0
  43. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/d4e5f6a7b8c9_alerts.py +0 -0
  44. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/d6e7f8a9b0c1_dataset_versioning.py +0 -0
  45. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/d9e0f1a2b3c4_note_threads.py +0 -0
  46. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/e0f1a2b3c4d5_tenant_suspend.py +0 -0
  47. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/e1f2a3b4c5d6_audit_log.py +0 -0
  48. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/e5f6a7b8c9d0_admin.py +0 -0
  49. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/e7f8a9b0c1d2_saved_views.py +0 -0
  50. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/f1a2b3c4d5e6_project_invites.py +0 -0
  51. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/f2a3b4c5d6e7_run_hot_path_indexes.py +0 -0
  52. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/f6a7b8c9d0e1_interactive_debugging.py +0 -0
  53. {provekit-0.7.0 → provekit-0.7.1}/provekit/migrations/versions/f8a9b0c1d2e3_webhook_subscriptions.py +0 -0
  54. {provekit-0.7.0 → provekit-0.7.1}/provekit/models.py +0 -0
  55. {provekit-0.7.0 → provekit-0.7.1}/provekit/observability.py +0 -0
  56. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/__init__.py +0 -0
  57. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/activity.py +0 -0
  58. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/admin.py +0 -0
  59. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/alerts.py +0 -0
  60. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/apikeys.py +0 -0
  61. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/auth.py +0 -0
  62. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/automation.py +0 -0
  63. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/dataset_writes.py +0 -0
  64. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/datasets.py +0 -0
  65. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/digests.py +0 -0
  66. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/evaluators.py +0 -0
  67. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/experiments.py +0 -0
  68. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/export.py +0 -0
  69. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/flows.py +0 -0
  70. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/metrics.py +0 -0
  71. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/playground.py +0 -0
  72. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/projects.py +0 -0
  73. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/prompts.py +0 -0
  74. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/review.py +0 -0
  75. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/scim.py +0 -0
  76. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/sso.py +0 -0
  77. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/traces.py +0 -0
  78. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/views.py +0 -0
  79. {provekit-0.7.0 → provekit-0.7.1}/provekit/routers/webhooks.py +0 -0
  80. {provekit-0.7.0 → provekit-0.7.1}/provekit/scorers.py +0 -0
  81. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/__init__.py +0 -0
  82. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/apikey.py +0 -0
  83. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/audit.py +0 -0
  84. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/auth.py +0 -0
  85. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/automation.py +0 -0
  86. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/custom_scorers.py +0 -0
  87. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/datasets.py +0 -0
  88. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/deploy.py +0 -0
  89. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/digests.py +0 -0
  90. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/email.py +0 -0
  91. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/errors.py +0 -0
  92. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/export.py +0 -0
  93. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/export_schedule.py +0 -0
  94. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/fleet.py +0 -0
  95. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/flow_trace.py +0 -0
  96. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/impersonation.py +0 -0
  97. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/invites.py +0 -0
  98. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/limits.py +0 -0
  99. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/llm_client.py +0 -0
  100. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/mentions.py +0 -0
  101. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/netguard.py +0 -0
  102. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/notify.py +0 -0
  103. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/oidc.py +0 -0
  104. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/otel.py +0 -0
  105. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/partitions.py +0 -0
  106. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/payloads.py +0 -0
  107. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/pricing.py +0 -0
  108. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/prompts.py +0 -0
  109. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/redact.py +0 -0
  110. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/replay.py +0 -0
  111. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/roles.py +0 -0
  112. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/rollups.py +0 -0
  113. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/scim.py +0 -0
  114. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/sealing.py +0 -0
  115. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/search.py +0 -0
  116. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/seed.py +0 -0
  117. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/share.py +0 -0
  118. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/spool.py +0 -0
  119. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/stats.py +0 -0
  120. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/tenant.py +0 -0
  121. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/usage.py +0 -0
  122. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/webhooks.py +0 -0
  123. {provekit-0.7.0 → provekit-0.7.1}/provekit/services/workspace.py +0 -0
  124. {provekit-0.7.0 → provekit-0.7.1}/provekit/vcr.py +0 -0
  125. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/dependency_links.txt +0 -0
  126. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/entry_points.txt +0 -0
  127. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/requires.txt +0 -0
  128. {provekit-0.7.0 → provekit-0.7.1}/provekit.egg-info/top_level.txt +0 -0
  129. {provekit-0.7.0 → provekit-0.7.1}/setup.cfg +0 -0
  130. {provekit-0.7.0 → provekit-0.7.1}/tests/test_account_recovery.py +0 -0
  131. {provekit-0.7.0 → provekit-0.7.1}/tests/test_activity.py +0 -0
  132. {provekit-0.7.0 → provekit-0.7.1}/tests/test_admin.py +0 -0
  133. {provekit-0.7.0 → provekit-0.7.1}/tests/test_alerts.py +0 -0
  134. {provekit-0.7.0 → provekit-0.7.1}/tests/test_apikeys.py +0 -0
  135. {provekit-0.7.0 → provekit-0.7.1}/tests/test_auth.py +0 -0
  136. {provekit-0.7.0 → provekit-0.7.1}/tests/test_auth_hardening.py +0 -0
  137. {provekit-0.7.0 → provekit-0.7.1}/tests/test_autoinstrument.py +0 -0
  138. {provekit-0.7.0 → provekit-0.7.1}/tests/test_automation.py +0 -0
  139. {provekit-0.7.0 → provekit-0.7.1}/tests/test_buffer.py +0 -0
  140. {provekit-0.7.0 → provekit-0.7.1}/tests/test_calibration.py +0 -0
  141. {provekit-0.7.0 → provekit-0.7.1}/tests/test_cli.py +0 -0
  142. {provekit-0.7.0 → provekit-0.7.1}/tests/test_clock_skew.py +0 -0
  143. {provekit-0.7.0 → provekit-0.7.1}/tests/test_conformance.py +0 -0
  144. {provekit-0.7.0 → provekit-0.7.1}/tests/test_cov_limits_auth.py +0 -0
  145. {provekit-0.7.0 → provekit-0.7.1}/tests/test_coverage_extra.py +0 -0
  146. {provekit-0.7.0 → provekit-0.7.1}/tests/test_custom_scorers.py +0 -0
  147. {provekit-0.7.0 → provekit-0.7.1}/tests/test_dataset_snapshots.py +0 -0
  148. {provekit-0.7.0 → provekit-0.7.1}/tests/test_dataset_versioning.py +0 -0
  149. {provekit-0.7.0 → provekit-0.7.1}/tests/test_datasets.py +0 -0
  150. {provekit-0.7.0 → provekit-0.7.1}/tests/test_dialects.py +0 -0
  151. {provekit-0.7.0 → provekit-0.7.1}/tests/test_digests.py +0 -0
  152. {provekit-0.7.0 → provekit-0.7.1}/tests/test_doctor.py +0 -0
  153. {provekit-0.7.0 → provekit-0.7.1}/tests/test_error_messages.py +0 -0
  154. {provekit-0.7.0 → provekit-0.7.1}/tests/test_eval.py +0 -0
  155. {provekit-0.7.0 → provekit-0.7.1}/tests/test_evaluators.py +0 -0
  156. {provekit-0.7.0 → provekit-0.7.1}/tests/test_experiments.py +0 -0
  157. {provekit-0.7.0 → provekit-0.7.1}/tests/test_export.py +0 -0
  158. {provekit-0.7.0 → provekit-0.7.1}/tests/test_export_schedule.py +0 -0
  159. {provekit-0.7.0 → provekit-0.7.1}/tests/test_feedback.py +0 -0
  160. {provekit-0.7.0 → provekit-0.7.1}/tests/test_fleet.py +0 -0
  161. {provekit-0.7.0 → provekit-0.7.1}/tests/test_flows.py +0 -0
  162. {provekit-0.7.0 → provekit-0.7.1}/tests/test_grpc_ingest.py +0 -0
  163. {provekit-0.7.0 → provekit-0.7.1}/tests/test_hardening.py +0 -0
  164. {provekit-0.7.0 → provekit-0.7.1}/tests/test_impersonation.py +0 -0
  165. {provekit-0.7.0 → provekit-0.7.1}/tests/test_index_coverage.py +0 -0
  166. {provekit-0.7.0 → provekit-0.7.1}/tests/test_invites.py +0 -0
  167. {provekit-0.7.0 → provekit-0.7.1}/tests/test_key_read_api.py +0 -0
  168. {provekit-0.7.0 → provekit-0.7.1}/tests/test_mcp.py +0 -0
  169. {provekit-0.7.0 → provekit-0.7.1}/tests/test_mcp_writes.py +0 -0
  170. {provekit-0.7.0 → provekit-0.7.1}/tests/test_metrics.py +0 -0
  171. {provekit-0.7.0 → provekit-0.7.1}/tests/test_migrations.py +0 -0
  172. {provekit-0.7.0 → provekit-0.7.1}/tests/test_netguard.py +0 -0
  173. {provekit-0.7.0 → provekit-0.7.1}/tests/test_note_threads.py +0 -0
  174. {provekit-0.7.0 → provekit-0.7.1}/tests/test_notify.py +0 -0
  175. {provekit-0.7.0 → provekit-0.7.1}/tests/test_observability.py +0 -0
  176. {provekit-0.7.0 → provekit-0.7.1}/tests/test_onboarding.py +0 -0
  177. {provekit-0.7.0 → provekit-0.7.1}/tests/test_otel.py +0 -0
  178. {provekit-0.7.0 → provekit-0.7.1}/tests/test_partitions.py +0 -0
  179. {provekit-0.7.0 → provekit-0.7.1}/tests/test_payload_offload.py +0 -0
  180. {provekit-0.7.0 → provekit-0.7.1}/tests/test_playground.py +0 -0
  181. {provekit-0.7.0 → provekit-0.7.1}/tests/test_playground_depth.py +0 -0
  182. {provekit-0.7.0 → provekit-0.7.1}/tests/test_playground_stream.py +0 -0
  183. {provekit-0.7.0 → provekit-0.7.1}/tests/test_pricing.py +0 -0
  184. {provekit-0.7.0 → provekit-0.7.1}/tests/test_projects.py +0 -0
  185. {provekit-0.7.0 → provekit-0.7.1}/tests/test_prompts_and_sessions.py +0 -0
  186. {provekit-0.7.0 → provekit-0.7.1}/tests/test_provenance.py +0 -0
  187. {provekit-0.7.0 → provekit-0.7.1}/tests/test_quality_gates.py +0 -0
  188. {provekit-0.7.0 → provekit-0.7.1}/tests/test_quota.py +0 -0
  189. {provekit-0.7.0 → provekit-0.7.1}/tests/test_redact.py +0 -0
  190. {provekit-0.7.0 → provekit-0.7.1}/tests/test_redaction_corpus.py +0 -0
  191. {provekit-0.7.0 → provekit-0.7.1}/tests/test_regression_triage.py +0 -0
  192. {provekit-0.7.0 → provekit-0.7.1}/tests/test_reproducibility.py +0 -0
  193. {provekit-0.7.0 → provekit-0.7.1}/tests/test_retention.py +0 -0
  194. {provekit-0.7.0 → provekit-0.7.1}/tests/test_review.py +0 -0
  195. {provekit-0.7.0 → provekit-0.7.1}/tests/test_roles.py +0 -0
  196. {provekit-0.7.0 → provekit-0.7.1}/tests/test_rollups.py +0 -0
  197. {provekit-0.7.0 → provekit-0.7.1}/tests/test_scim.py +0 -0
  198. {provekit-0.7.0 → provekit-0.7.1}/tests/test_scorers.py +0 -0
  199. {provekit-0.7.0 → provekit-0.7.1}/tests/test_scorers_extra.py +0 -0
  200. {provekit-0.7.0 → provekit-0.7.1}/tests/test_search.py +0 -0
  201. {provekit-0.7.0 → provekit-0.7.1}/tests/test_share.py +0 -0
  202. {provekit-0.7.0 → provekit-0.7.1}/tests/test_share_redaction.py +0 -0
  203. {provekit-0.7.0 → provekit-0.7.1}/tests/test_spool.py +0 -0
  204. {provekit-0.7.0 → provekit-0.7.1}/tests/test_sso.py +0 -0
  205. {provekit-0.7.0 → provekit-0.7.1}/tests/test_stats.py +0 -0
  206. {provekit-0.7.0 → provekit-0.7.1}/tests/test_step_through.py +0 -0
  207. {provekit-0.7.0 → provekit-0.7.1}/tests/test_tenant.py +0 -0
  208. {provekit-0.7.0 → provekit-0.7.1}/tests/test_trace_cost.py +0 -0
  209. {provekit-0.7.0 → provekit-0.7.1}/tests/test_trace_sdk.py +0 -0
  210. {provekit-0.7.0 → provekit-0.7.1}/tests/test_traces_tree.py +0 -0
  211. {provekit-0.7.0 → provekit-0.7.1}/tests/test_usage_metering.py +0 -0
  212. {provekit-0.7.0 → provekit-0.7.1}/tests/test_vcr.py +0 -0
  213. {provekit-0.7.0 → provekit-0.7.1}/tests/test_views.py +0 -0
  214. {provekit-0.7.0 → provekit-0.7.1}/tests/test_webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: provekit
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Drop-in agent tracing — add one decorator, get a project key, review every run your agent makes.
5
5
  Author: ProveKit contributors
6
6
  License: MIT
@@ -18,6 +18,8 @@ import json
18
18
 
19
19
  import httpx
20
20
 
21
+ from .trace import _no_self_trace
22
+
21
23
  from . import scorers as _scorers
22
24
  from . import trace as _trace
23
25
 
@@ -25,24 +27,40 @@ _TIMEOUT = 60
25
27
 
26
28
 
27
29
  def _get(endpoint, headers, path):
28
- r = httpx.get(f"{endpoint}{path}", headers=headers, timeout=_TIMEOUT, follow_redirects=False)
30
+ with _no_self_trace():
31
+ r = httpx.get(f"{endpoint}{path}", headers=headers, timeout=_TIMEOUT, follow_redirects=False)
29
32
  r.raise_for_status()
30
33
  return r.json()
31
34
 
32
35
 
33
36
  def _post(endpoint, headers, path, body):
34
- r = httpx.post(f"{endpoint}{path}", headers=headers, json=body, timeout=_TIMEOUT, follow_redirects=False)
37
+ with _no_self_trace():
38
+ r = httpx.post(f"{endpoint}{path}", headers=headers, json=body, timeout=_TIMEOUT,
39
+ follow_redirects=False)
35
40
  r.raise_for_status()
36
41
  return r.json()
37
42
 
38
43
 
39
44
  def _resolve_dataset_id(endpoint, headers, dataset) -> int:
45
+ """Accept an id or a name — and an id that arrived as a string.
46
+
47
+ The id is a number everywhere it is shown (the portal, `provekit datasets list`), and the
48
+ two places it is most often read from — an environment variable and a CLI argument — hand
49
+ it back as text. `evaluate("2", …)` then fell through to the name lookup and reported
50
+ `dataset '2' not found`, which is true and completely misleading: the dataset exists, and
51
+ nothing in the message suggests the type is what is wrong.
52
+ """
40
53
  if isinstance(dataset, int):
41
54
  return dataset
55
+ if isinstance(dataset, str) and dataset.strip().isdigit():
56
+ return int(dataset.strip())
57
+ names = []
42
58
  for d in _get(endpoint, headers, "/v1/datasets"):
43
59
  if d.get("name") == dataset:
44
60
  return d["id"]
45
- raise ValueError(f"dataset {dataset!r} not found")
61
+ names.append(d.get("name"))
62
+ raise ValueError(
63
+ f"dataset {dataset!r} not found — this project has: {', '.join(map(str, names)) or 'none'}")
46
64
 
47
65
 
48
66
  def evaluate(dataset, target, scorers, *, name: str = "experiment") -> dict:
@@ -225,10 +225,11 @@ def calibrate(rows, *, pass_at: float = PASS_AT, judge_name: str = "", human_nam
225
225
  # label more. The rates are the part that would get quoted as a credibility claim, so
226
226
  # they are withheld rather than published with a disclaimer nobody carries forward.
227
227
  out["caution"] = (
228
- f"{n} trace(s) carry both a human label and a judge score fewer than "
229
- f"{MIN_LABELLED_N}, so no agreement rate, kappa or verdict is reported. A "
230
- f"calibration number from a handful of labels is worse than none: it gets quoted. "
231
- f"Label more traces in the portal.")
228
+ f"Only {n} run{'' if n == 1 else 's'} {'has' if n == 1 else 'have'} been judged both "
229
+ f"ways by you and by the scorer. We need at least {MIN_LABELLED_N} before the "
230
+ f"numbers mean anything. A score from a handful of examples looks solid and is not, "
231
+ f"and once someone quotes it the damage is done — so we show nothing instead. "
232
+ f"Judge a few more runs in the Review queue.")
232
233
  return out
233
234
 
234
235
  out["agreement"] = (a + d) / n
@@ -160,6 +160,33 @@ def _span_to_otlp(span) -> dict:
160
160
  return out
161
161
 
162
162
 
163
+ @contextlib.contextmanager
164
+ def _no_self_trace():
165
+ """Don't instrument ProveKit's own HTTP calls.
166
+
167
+ `provekit[http]` instruments httpx, and the SDK talks to the portal over httpx — so
168
+ exporting a batch, fetching a prompt and posting a score were each captured as spans, which
169
+ were then exported, which produced more spans. They arrive parentless, so they land in the
170
+ trace list as top-level runs named "GET" and "POST" carrying no model, no tokens and no
171
+ input: in a first real run of the demo agent, 19 of 24 traces were this noise.
172
+
173
+ It is worse than clutter. Those rows are counted: they drag the error rate and p95 toward
174
+ the latency of ProveKit's own API, and they push real runs off the first page of a list
175
+ people scan by eye.
176
+
177
+ Best-effort by design — the helper only exists once an instrumentation package is
178
+ installed, and tracing must never be the thing that breaks a customer's process, so a
179
+ missing import degrades to "no suppression" rather than raising.
180
+ """
181
+ try:
182
+ from opentelemetry.instrumentation.utils import suppress_instrumentation
183
+ except Exception: # noqa: BLE001 — optional dependency
184
+ yield
185
+ return
186
+ with suppress_instrumentation():
187
+ yield
188
+
189
+
163
190
  class _ProveKitExporter:
164
191
  """A minimal OTel SpanExporter that ships spans to ProveKit's /v1/traces as OTLP-JSON.
165
192
 
@@ -179,8 +206,9 @@ class _ProveKitExporter:
179
206
  by never looking — silently drops exactly the spans the retry path exists for.
180
207
  """
181
208
  import httpx
182
- r = httpx.post(self._url, json=body, headers=self._headers, timeout=5,
183
- follow_redirects=False)
209
+ with _no_self_trace():
210
+ r = httpx.post(self._url, json=body, headers=self._headers, timeout=5,
211
+ follow_redirects=False)
184
212
  if r.status_code >= 400:
185
213
  log.debug("provekit trace export rejected: HTTP %s", r.status_code)
186
214
  return False
@@ -453,9 +481,10 @@ def get_prompt(name: str, *, label: str = "", key: str = "", default=None) -> di
453
481
  return default
454
482
  try:
455
483
  import httpx
456
- r = httpx.get(f"{endpoint}/v1/prompts/{name}",
457
- params={"label": label, "key": key},
458
- headers={"Authorization": f"Bearer {api_key}"}, timeout=5)
484
+ with _no_self_trace():
485
+ r = httpx.get(f"{endpoint}/v1/prompts/{name}",
486
+ params={"label": label, "key": key},
487
+ headers={"Authorization": f"Bearer {api_key}"}, timeout=5)
459
488
  if r.status_code >= 400:
460
489
  log.debug("provekit: prompt %r fetch returned %s", name, r.status_code)
461
490
  return default
@@ -499,8 +528,10 @@ def score(name: str, *, score: float | None = None, value: str | None = None,
499
528
  body = {"name": name, "score": score, "value": value, "comment": comment, "source": "sdk"}
500
529
  try:
501
530
  import httpx
502
- httpx.post(f"{_endpoint}/v1/traces/{trace_id}/feedback", json=body,
503
- headers={"Authorization": f"Bearer {_api_key}"}, timeout=5, follow_redirects=False)
531
+ with _no_self_trace():
532
+ httpx.post(f"{_endpoint}/v1/traces/{trace_id}/feedback", json=body,
533
+ headers={"Authorization": f"Bearer {_api_key}"}, timeout=5,
534
+ follow_redirects=False)
504
535
  return True
505
536
  except Exception as exc: # never let a feedback post surface into the user's app
506
537
  log.debug("provekit score post failed: %s", exc)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: provekit
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Drop-in agent tracing — add one decorator, get a project key, review every run your agent makes.
5
5
  Author: ProveKit contributors
6
6
  License: MIT
@@ -195,6 +195,7 @@ tests/test_scim.py
195
195
  tests/test_scorers.py
196
196
  tests/test_scorers_extra.py
197
197
  tests/test_search.py
198
+ tests/test_self_trace.py
198
199
  tests/test_share.py
199
200
  tests/test_share_redaction.py
200
201
  tests/test_spool.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "provekit"
3
- version = "0.7.0"
3
+ version = "0.7.1"
4
4
  description = "Drop-in agent tracing — add one decorator, get a project key, review every run your agent makes."
5
5
  requires-python = ">=3.11"
6
6
  readme = "README.md"
@@ -0,0 +1,86 @@
1
+ """The SDK must not trace its own calls to the portal (#noise).
2
+
3
+ `provekit[http]` instruments httpx, and the SDK talks to the portal over httpx. Without
4
+ suppression, exporting a batch, fetching a prompt and posting a score each produced their own
5
+ parentless span, which arrived in the customer's trace list as a top-level run named "GET" or
6
+ "POST" with no model, no tokens and no input. In a first real run of the bundled demo agent,
7
+ 19 of 24 traces were this. They are also counted, so they drag error rate and p95 toward the
8
+ latency of ProveKit's own API.
9
+ """
10
+ from provekit import trace as pk_trace
11
+
12
+
13
+ def test_the_suppression_helper_is_a_context_manager():
14
+ with pk_trace._no_self_trace():
15
+ pass
16
+
17
+
18
+ def test_it_degrades_to_a_no_op_without_the_instrumentation_package(monkeypatch):
19
+ """Tracing must never be the thing that breaks a customer's process, so a missing optional
20
+ import has to mean "no suppression", not an exception."""
21
+ import builtins
22
+ real = builtins.__import__
23
+
24
+ def _no_otel_utils(name, *a, **kw):
25
+ if name == "opentelemetry.instrumentation.utils":
26
+ raise ImportError("not installed")
27
+ return real(name, *a, **kw)
28
+
29
+ monkeypatch.setattr(builtins, "__import__", _no_otel_utils)
30
+ with pk_trace._no_self_trace():
31
+ pass # did not raise
32
+
33
+
34
+ def test_every_sdk_call_to_the_portal_is_wrapped():
35
+ """A drift guard. A new httpx call added to the SDK without suppression re-opens the bug,
36
+ and the symptom (junk traces in someone else's portal) never shows up in our own tests."""
37
+ import inspect
38
+ import re
39
+
40
+ from provekit import eval as pk_eval
41
+
42
+ for mod in (pk_trace, pk_eval):
43
+ src = inspect.getsource(mod)
44
+ for m in re.finditer(r'^(\s*)(?:r = )?httpx\.(get|post)\(', src, re.M):
45
+ line_no = src[:m.start()].count("\n") + 1
46
+ before = src[:m.start()].rsplit("\n", 3)[-3:]
47
+ assert any("_no_self_trace()" in b for b in before), (
48
+ f"{mod.__name__}:{line_no} calls httpx.{m.group(2)} outside _no_self_trace() — "
49
+ "it will appear as a junk trace in the customer's own portal")
50
+
51
+
52
+ # ---------------------------------------------------------------- dataset id as a string
53
+
54
+ def test_a_dataset_id_that_arrived_as_text_still_resolves():
55
+ """An id read from os.environ or argv is a str. It used to fall through to the name lookup
56
+ and report `dataset '2' not found` — true, and entirely misleading, because the dataset is
57
+ right there and the type is what was wrong."""
58
+ from provekit.eval import _resolve_dataset_id
59
+
60
+ def _never_called(*a, **kw):
61
+ raise AssertionError("a numeric id must not need a network lookup")
62
+
63
+ import provekit.eval as ev
64
+ real = ev._get
65
+ ev._get = _never_called
66
+ try:
67
+ assert _resolve_dataset_id("http://x", {}, "2") == 2
68
+ assert _resolve_dataset_id("http://x", {}, " 7 ") == 7
69
+ assert _resolve_dataset_id("http://x", {}, 3) == 3
70
+ finally:
71
+ ev._get = real
72
+
73
+
74
+ def test_an_unknown_name_says_what_the_project_does_have():
75
+ """"not found" alone leaves you guessing whether the name is wrong, the project is wrong,
76
+ or the key is. Listing what is actually there settles it in one line."""
77
+ import pytest
78
+
79
+ import provekit.eval as ev
80
+ real = ev._get
81
+ ev._get = lambda *a, **kw: [{"id": 1, "name": "support-qa"}, {"id": 2, "name": "billing"}]
82
+ try:
83
+ with pytest.raises(ValueError, match="support-qa, billing"):
84
+ ev._resolve_dataset_id("http://x", {}, "typo-name")
85
+ finally:
86
+ ev._get = real
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes