evalcraft 0.2.0__tar.gz → 0.2.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 (291) hide show
  1. {evalcraft-0.2.0 → evalcraft-0.2.1}/CHANGELOG.md +5 -0
  2. {evalcraft-0.2.0 → evalcraft-0.2.1}/PKG-INFO +1 -1
  3. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/__init__.py +1 -1
  4. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/main.py +3 -3
  5. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/evalcraft.toml +1 -1
  6. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cloud/client.py +31 -14
  7. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/core/models.py +1 -1
  8. {evalcraft-0.2.0 → evalcraft-0.2.1}/pyproject.toml +1 -1
  9. {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/seed_demo.py +3 -3
  10. {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/smoke_test.py +1 -1
  11. evalcraft-0.2.1/site/CNAME +1 -0
  12. {evalcraft-0.2.0 → evalcraft-0.2.1}/site/index.html +3 -3
  13. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_cloud.py +18 -7
  14. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_e2e_pipeline.py +1 -1
  15. evalcraft-0.2.0/site/CNAME +0 -1
  16. {evalcraft-0.2.0 → evalcraft-0.2.1}/.env.example +0 -0
  17. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  18. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  19. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/design-partner-feedback.md +0 -0
  20. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/workflows/ci.yml +0 -0
  22. {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/workflows/publish.yml +0 -0
  23. {evalcraft-0.2.0 → evalcraft-0.2.1}/.gitignore +0 -0
  24. {evalcraft-0.2.0 → evalcraft-0.2.1}/CONTRIBUTING.md +0 -0
  25. {evalcraft-0.2.0 → evalcraft-0.2.1}/LICENSE +0 -0
  26. {evalcraft-0.2.0 → evalcraft-0.2.1}/Makefile +0 -0
  27. {evalcraft-0.2.0 → evalcraft-0.2.1}/README.md +0 -0
  28. {evalcraft-0.2.0 → evalcraft-0.2.1}/action.yml +0 -0
  29. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/Dockerfile +0 -0
  30. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/env.py +0 -0
  31. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/script.py.mako +0 -0
  32. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/versions/.gitkeep +0 -0
  33. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/versions/001_initial.py +0 -0
  34. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic.ini +0 -0
  35. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/__init__.py +0 -0
  36. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/__init__.py +0 -0
  37. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/auth.py +0 -0
  38. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/cassettes.py +0 -0
  39. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/golden_sets.py +0 -0
  40. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/projects.py +0 -0
  41. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/regressions.py +0 -0
  42. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/webhooks.py +0 -0
  43. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/cache.py +0 -0
  44. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/config.py +0 -0
  45. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/database.py +0 -0
  46. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/logging_config.py +0 -0
  47. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/main.py +0 -0
  48. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/__init__.py +0 -0
  49. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/cassette.py +0 -0
  50. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/golden_set.py +0 -0
  51. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/project.py +0 -0
  52. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/regression.py +0 -0
  53. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/user.py +0 -0
  54. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/schemas/__init__.py +0 -0
  55. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/schemas/api.py +0 -0
  56. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/alert_service.py +0 -0
  57. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/analytics_service.py +0 -0
  58. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/cassette_service.py +0 -0
  59. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/regression_service.py +0 -0
  60. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/entrypoint.sh +0 -0
  61. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/requirements.txt +0 -0
  62. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/conftest.py +0 -0
  63. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_auth.py +0 -0
  64. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_cassettes.py +0 -0
  65. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_golden_sets.py +0 -0
  66. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_projects.py +0 -0
  67. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_regressions.py +0 -0
  68. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_webhooks.py +0 -0
  69. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/.gitignore +0 -0
  70. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/Dockerfile +0 -0
  71. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/README.md +0 -0
  72. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/eslint.config.js +0 -0
  73. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/index.html +0 -0
  74. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/nginx.conf +0 -0
  75. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/package-lock.json +0 -0
  76. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/package.json +0 -0
  77. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/public/vite.svg +0 -0
  78. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/App.css +0 -0
  79. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/App.tsx +0 -0
  80. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/ErrorBoundary.test.tsx +0 -0
  81. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/Skeleton.test.tsx +0 -0
  82. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/api.test.ts +0 -0
  83. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/assets/react.svg +0 -0
  84. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateGoldenSetModal.tsx +0 -0
  85. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateProjectModal.tsx +0 -0
  86. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/ErrorBoundary.tsx +0 -0
  87. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Layout.tsx +0 -0
  88. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/MetricCard.tsx +0 -0
  89. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Sidebar.tsx +0 -0
  90. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Skeleton.tsx +0 -0
  91. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/StatusBadge.tsx +0 -0
  92. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Toast.tsx +0 -0
  93. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/UploadCassetteModal.tsx +0 -0
  94. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/context/AuthContext.tsx +0 -0
  95. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/hooks/useApi.ts +0 -0
  96. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/index.css +0 -0
  97. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/main.tsx +0 -0
  98. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Analytics.tsx +0 -0
  99. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/CassetteDetail.tsx +0 -0
  100. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Cassettes.tsx +0 -0
  101. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Dashboard.tsx +0 -0
  102. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/GoldenSetDetail.tsx +0 -0
  103. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/GoldenSets.tsx +0 -0
  104. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Login.tsx +0 -0
  105. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Regressions.tsx +0 -0
  106. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Settings.tsx +0 -0
  107. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/services/api.ts +0 -0
  108. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/test-setup.ts +0 -0
  109. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.app.json +0 -0
  110. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.json +0 -0
  111. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.node.json +0 -0
  112. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/vite.config.ts +0 -0
  113. {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/vitest.config.ts +0 -0
  114. {evalcraft-0.2.0 → evalcraft-0.2.1}/docker-compose.production.yml +0 -0
  115. {evalcraft-0.2.0 → evalcraft-0.2.1}/docker-compose.yml +0 -0
  116. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/index.md +0 -0
  117. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/logo.png +0 -0
  118. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/anthropic.md +0 -0
  119. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/crewai.md +0 -0
  120. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/langgraph.md +0 -0
  121. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/openai.md +0 -0
  122. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/capture.md +0 -0
  123. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/changelog.md +0 -0
  124. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/ci-cd.md +0 -0
  125. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/cli.md +0 -0
  126. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/concepts.md +0 -0
  127. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/five-minute-case-study.md +0 -0
  128. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/index.md +0 -0
  129. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/live-eval.md +0 -0
  130. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/mock.md +0 -0
  131. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/pytest-plugin.md +0 -0
  132. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/quickstart.md +0 -0
  133. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/replay.md +0 -0
  134. {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/scorers.md +0 -0
  135. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/__init__.py +0 -0
  136. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/anthropic_adapter.py +0 -0
  137. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/autogen_adapter.py +0 -0
  138. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/crewai_adapter.py +0 -0
  139. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/gemini_adapter.py +0 -0
  140. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/langgraph_adapter.py +0 -0
  141. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/llamaindex_adapter.py +0 -0
  142. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/openai_adapter.py +0 -0
  143. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/pydantic_ai_adapter.py +0 -0
  144. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/__init__.py +0 -0
  145. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/email.py +0 -0
  146. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/slack.py +0 -0
  147. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/webhook.py +0 -0
  148. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/capture/__init__.py +0 -0
  149. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/capture/recorder.py +0 -0
  150. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/__init__.py +0 -0
  151. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/doctor_cmd.py +0 -0
  152. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/generate_cmd.py +0 -0
  153. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/init_cmd.py +0 -0
  154. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/__init__.py +0 -0
  155. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/conftest.py +0 -0
  156. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_anthropic.py +0 -0
  157. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_crewai.py +0 -0
  158. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_generic.py +0 -0
  159. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_langgraph.py +0 -0
  160. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_openai.py +0 -0
  161. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cloud/__init__.py +0 -0
  162. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/core/__init__.py +0 -0
  163. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/__init__.py +0 -0
  164. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/_utils.py +0 -0
  165. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/hallucination.py +0 -0
  166. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/judge_cache.py +0 -0
  167. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/jury.py +0 -0
  168. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/live.py +0 -0
  169. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/llm_judge.py +0 -0
  170. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/pairwise.py +0 -0
  171. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/rag_scorers.py +0 -0
  172. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/scorers/__init__.py +0 -0
  173. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/statistical.py +0 -0
  174. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/golden/__init__.py +0 -0
  175. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/golden/manager.py +0 -0
  176. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/__init__.py +0 -0
  177. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/llm.py +0 -0
  178. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/tool.py +0 -0
  179. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/pytest_plugin/__init__.py +0 -0
  180. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/pytest_plugin/plugin.py +0 -0
  181. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/__init__.py +0 -0
  182. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/detector.py +0 -0
  183. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/trend.py +0 -0
  184. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/__init__.py +0 -0
  185. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/engine.py +0 -0
  186. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/network_guard.py +0 -0
  187. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/sanitize/__init__.py +0 -0
  188. {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/sanitize/redactor.py +0 -0
  189. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/README.md +0 -0
  190. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/agent.py +0 -0
  191. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/record_cassettes.py +0 -0
  192. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/requirements.txt +0 -0
  193. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/cassettes/auth_middleware_review.json +0 -0
  194. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/cassettes/db_pool_refactor_review.json +0 -0
  195. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/test_code_review_agent.py +0 -0
  196. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/basic_capture.py +0 -0
  197. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/.github/workflows/eval.yml +0 -0
  198. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/README.md +0 -0
  199. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/evalcraft-ci.yml +0 -0
  200. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/evalcraft_gate.py +0 -0
  201. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/requirements.txt +0 -0
  202. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/tests/test_ci_gate.py +0 -0
  203. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/example-ci-gate.yml +0 -0
  204. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/README.md +0 -0
  205. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/record_cassettes.py +0 -0
  206. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/requirements.txt +0 -0
  207. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/cassettes/equipment_stipend.json +0 -0
  208. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/cassettes/remote_work_policy.json +0 -0
  209. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/test_rag_workflow.py +0 -0
  210. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/workflow.py +0 -0
  211. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/README.md +0 -0
  212. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/agent.py +0 -0
  213. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/build_golden.py +0 -0
  214. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/record_cassettes.py +0 -0
  215. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/requirements.txt +0 -0
  216. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/damaged_item.json +0 -0
  217. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/order_tracking.json +0 -0
  218. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/return_request.json +0 -0
  219. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/test_golden.py +0 -0
  220. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/test_support_agent.py +0 -0
  221. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/replay_and_diff.py +0 -0
  222. {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/test_with_mocks.py +0 -0
  223. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/dm-templates.md +0 -0
  224. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/outreach-targets.md +0 -0
  225. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/outreach-tracker.md +0 -0
  226. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/reddit-langchain.md +0 -0
  227. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/reddit-python.md +0 -0
  228. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/show-hn.md +0 -0
  229. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/tracking-dashboard.md +0 -0
  230. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/twitter-thread.md +0 -0
  231. {evalcraft-0.2.0 → evalcraft-0.2.1}/launch-posts.md +0 -0
  232. {evalcraft-0.2.0 → evalcraft-0.2.1}/mkdocs.yml +0 -0
  233. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/package-lock.json +0 -0
  234. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/package.json +0 -0
  235. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/gemini.ts +0 -0
  236. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/openai.ts +0 -0
  237. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/vercel-ai.ts +0 -0
  238. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/capture/recorder.ts +0 -0
  239. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/core/models.ts +0 -0
  240. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/core/types.ts +0 -0
  241. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/llm-judge.ts +0 -0
  242. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/rag-scorers.ts +0 -0
  243. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/scorers.ts +0 -0
  244. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/index.ts +0 -0
  245. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/mock/llm.ts +0 -0
  246. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/mock/tool.ts +0 -0
  247. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/replay/engine.ts +0 -0
  248. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/types/externals.d.ts +0 -0
  249. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/capture.test.ts +0 -0
  250. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/mock.test.ts +0 -0
  251. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/models.test.ts +0 -0
  252. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/replay.test.ts +0 -0
  253. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/scorers.test.ts +0 -0
  254. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/vercel-ai.test.ts +0 -0
  255. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tsconfig.json +0 -0
  256. {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/vitest.config.ts +0 -0
  257. {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/requirements.txt +0 -0
  258. {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/validate_with_openai.py +0 -0
  259. {evalcraft-0.2.0 → evalcraft-0.2.1}/site/logo.png +0 -0
  260. {evalcraft-0.2.0 → evalcraft-0.2.1}/site/robots.txt +0 -0
  261. {evalcraft-0.2.0 → evalcraft-0.2.1}/site/sitemap.xml +0 -0
  262. {evalcraft-0.2.0 → evalcraft-0.2.1}/site/thank-you.html +0 -0
  263. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/conftest.py +0 -0
  264. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/regression/test_trend_detector.py +0 -0
  265. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_alerts.py +0 -0
  266. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_anthropic_adapter.py +0 -0
  267. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_doctor.py +0 -0
  268. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_gemini_adapter.py +0 -0
  269. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_generate_tests.py +0 -0
  270. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_golden.py +0 -0
  271. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_hallucination.py +0 -0
  272. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_init.py +0 -0
  273. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_judge_cache.py +0 -0
  274. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_jury.py +0 -0
  275. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_live_eval.py +0 -0
  276. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_llm_judge.py +0 -0
  277. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_mock_llm.py +0 -0
  278. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_mock_tool.py +0 -0
  279. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_models.py +0 -0
  280. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_network_guard.py +0 -0
  281. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_pairwise.py +0 -0
  282. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_provenance.py +0 -0
  283. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_pydantic_ai_adapter.py +0 -0
  284. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_rag_scorers.py +0 -0
  285. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_recorder.py +0 -0
  286. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_regression.py +0 -0
  287. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_replay.py +0 -0
  288. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_sanitize.py +0 -0
  289. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_scorer_offline.py +0 -0
  290. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_scorers.py +0 -0
  291. {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_statistical.py +0 -0
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] — 2026-05-30
9
+
10
+ ### Fixed
11
+ - **Removed references to the unregistered `evalcraft.dev` domain.** The cloud client and the `evalcraft cloud` CLI no longer default to a non-existent `api.evalcraft.dev` endpoint. There is **no public hosted service** — configure a self-hosted dashboard URL explicitly via `base_url=`, the `EVALCRAFT_BASE_URL` env var, or `~/.evalcraft/config.json`. A cloud call with no URL configured now raises a clear, self-host-pointing error instead of failing against a dead host. Also scrubbed the dead domain from the `evalcraft init` config template and the landing-page contact links.
12
+
8
13
  ## [0.2.0] — 2026-05-30
9
14
 
10
15
  Ships everything developed since the initial `0.1.0` PyPI upload — a much larger
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evalcraft
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: VCR for AI agents — record agent runs as cassettes and replay them deterministically in CI for $0.
5
5
  Project-URL: Homepage, https://github.com/beyhangl/evalcraft
6
6
  Project-URL: Repository, https://github.com/beyhangl/evalcraft
@@ -4,7 +4,7 @@ Record agent runs as cassettes and replay them deterministically in CI for $0;
4
4
  mock LLMs/tools, score runs, and catch real model drift with live-eval.
5
5
  """
6
6
 
7
- __version__ = "0.2.0"
7
+ __version__ = "0.2.1"
8
8
 
9
9
  from evalcraft.capture.recorder import CaptureContext, capture
10
10
  from evalcraft.cloud.client import EvalcraftCloud
@@ -58,7 +58,7 @@ _SPAN_COLORS: dict[SpanKind, str] = {
58
58
  # ─── CLI root ─────────────────────────────────────────────────────────────────
59
59
 
60
60
  @click.group()
61
- @click.version_option(version="0.2.0", prog_name="evalcraft")
61
+ @click.version_option(version="0.2.1", prog_name="evalcraft")
62
62
  def cli() -> None:
63
63
  """evalcraft — capture, replay, and evaluate AI agent runs."""
64
64
 
@@ -1111,8 +1111,8 @@ def cloud() -> None:
1111
1111
  @cloud.command("login")
1112
1112
  @click.option("--api-key", prompt="API key", hide_input=True,
1113
1113
  help="Your Evalcraft API key (ec_...)")
1114
- @click.option("--url", default="https://api.evalcraft.dev/v1",
1115
- help="Override API base URL")
1114
+ @click.option("--url", default="",
1115
+ help="Your self-hosted dashboard URL (optional; there is no public hosted service)")
1116
1116
  def cloud_login(api_key: str, url: str) -> None:
1117
1117
  """Save your API key to ~/.evalcraft/config.json.
1118
1118
 
@@ -37,4 +37,4 @@ auto_upload = false
37
37
 
38
38
  [cloud]
39
39
  # Override the Evalcraft cloud API endpoint.
40
- # base_url = "https://api.evalcraft.dev/v1"
40
+ # base_url = "http://localhost:8000/v1" # your self-hosted dashboard (no public service)
@@ -34,13 +34,11 @@ from typing import Any
34
34
 
35
35
  logger = logging.getLogger(__name__)
36
36
 
37
- # NOTE: The hosted Evalcraft dashboard/API is not yet publicly available.
38
- # This default points at the *planned* hosted endpoint; until it ships, set
39
- # ``base_url`` (or the ``base_url`` field in ~/.evalcraft/config.json) to your
40
- # own self-hosted dashboard see the ``dashboard/`` directory. All cloud
41
- # features are optional: the core capture / replay / eval workflow runs fully
42
- # offline and never contacts this endpoint.
43
- _DEFAULT_BASE_URL = "https://api.evalcraft.dev/v1"
37
+ # There is no public hosted Evalcraft API. Cloud features are optional and target
38
+ # a *self-hosted* dashboard (see the ``dashboard/`` directory); configure the
39
+ # endpoint explicitly via the ``base_url`` argument, the ``EVALCRAFT_BASE_URL``
40
+ # environment variable, or ``~/.evalcraft/config.json``. The core capture /
41
+ # replay / eval workflow runs fully offline and never contacts any endpoint.
44
42
  _CONFIG_DIR = Path.home() / ".evalcraft"
45
43
  _CONFIG_FILE = _CONFIG_DIR / "config.json"
46
44
  _QUEUE_DIR = _CONFIG_DIR / "queue"
@@ -104,7 +102,9 @@ class EvalcraftCloud:
104
102
  api_key: Bearer token (``ec_...``). If None, reads from
105
103
  ``~/.evalcraft/config.json`` or the ``EVALCRAFT_API_KEY``
106
104
  environment variable.
107
- base_url: Override the default API endpoint.
105
+ base_url: URL of your self-hosted Evalcraft dashboard. Required for any
106
+ cloud call — there is no public hosted service. Falls back to the
107
+ ``EVALCRAFT_BASE_URL`` env var, then ``~/.evalcraft/config.json``.
108
108
  timeout: Request timeout in seconds (default 30).
109
109
  max_retries: Maximum number of retry attempts for transient errors
110
110
  (default 3). Uses exponential backoff with jitter.
@@ -115,13 +115,13 @@ class EvalcraftCloud:
115
115
  def __init__(
116
116
  self,
117
117
  api_key: str | None = None,
118
- base_url: str = _DEFAULT_BASE_URL,
118
+ base_url: str | None = None,
119
119
  timeout: int = 30,
120
120
  max_retries: int = 3,
121
121
  queue_dir: Path | None = None,
122
122
  ):
123
123
  self.api_key = api_key or self._load_api_key()
124
- self.base_url = base_url.rstrip("/")
124
+ self.base_url = (base_url or self._load_base_url()).rstrip("/")
125
125
  self.timeout = timeout
126
126
  self.max_retries = max_retries
127
127
  self.queue_dir = queue_dir or _QUEUE_DIR
@@ -237,8 +237,8 @@ class EvalcraftCloud:
237
237
  # ──────────────────────────────────────────
238
238
 
239
239
  @staticmethod
240
- def save_config(api_key: str, base_url: str = _DEFAULT_BASE_URL) -> None:
241
- """Persist API key and base URL to ``~/.evalcraft/config.json``."""
240
+ def save_config(api_key: str, base_url: str = "") -> None:
241
+ """Persist the API key (and optional dashboard URL) to ``~/.evalcraft/config.json``."""
242
242
  _CONFIG_DIR.mkdir(parents=True, exist_ok=True)
243
243
  config: dict = {}
244
244
  if _CONFIG_FILE.exists():
@@ -247,7 +247,8 @@ class EvalcraftCloud:
247
247
  except Exception:
248
248
  pass
249
249
  config["api_key"] = api_key
250
- config["base_url"] = base_url
250
+ if base_url:
251
+ config["base_url"] = base_url
251
252
  _CONFIG_FILE.write_text(json.dumps(config, indent=2))
252
253
  _CONFIG_FILE.chmod(0o600)
253
254
 
@@ -288,6 +289,15 @@ class EvalcraftCloud:
288
289
  config = self.load_config()
289
290
  return str(config.get("api_key", ""))
290
291
 
292
+ def _load_base_url(self) -> str:
293
+ """Resolve the dashboard base URL from env or config (empty if unset)."""
294
+ import os
295
+ env_url = os.environ.get("EVALCRAFT_BASE_URL", "")
296
+ if env_url:
297
+ return env_url
298
+ config = self.load_config()
299
+ return str(config.get("base_url", ""))
300
+
291
301
  def _request(
292
302
  self,
293
303
  method: str,
@@ -307,11 +317,18 @@ class EvalcraftCloud:
307
317
  Raises:
308
318
  CloudUploadError: After max_retries exhausted or on 4xx errors.
309
319
  """
320
+ if not self.base_url:
321
+ raise CloudUploadError(
322
+ "No Evalcraft dashboard URL is configured. There is no public "
323
+ "hosted service — point the client at your own self-hosted "
324
+ "dashboard (see the dashboard/ directory) via base_url=..., the "
325
+ "EVALCRAFT_BASE_URL env var, or ~/.evalcraft/config.json."
326
+ )
310
327
  url = f"{self.base_url}{path}"
311
328
  body: bytes | None = None
312
329
  headers: dict[str, str] = {
313
330
  "Accept": "application/json",
314
- "User-Agent": "evalcraft-sdk/0.2.0",
331
+ "User-Agent": "evalcraft-sdk/0.2.1",
315
332
  }
316
333
  if self.api_key:
317
334
  headers["Authorization"] = f"Bearer {self.api_key}"
@@ -288,7 +288,7 @@ class Cassette:
288
288
  self.compute_metrics()
289
289
  self.compute_fingerprint()
290
290
  return {
291
- "evalcraft_version": "0.2.0",
291
+ "evalcraft_version": "0.2.1",
292
292
  "cassette": {
293
293
  "id": self.id,
294
294
  "name": self.name,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "evalcraft"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "VCR for AI agents — record agent runs as cassettes and replay them deterministically in CI for $0."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -258,7 +258,7 @@ def main():
258
258
  # 2. Sign up demo user
259
259
  print("Creating demo user...", end=" ")
260
260
  r = client.post("/auth/signup", json={
261
- "email": "demo@evalcraft.dev",
261
+ "email": "demo@example.com",
262
262
  "password": "demodemo123",
263
263
  "full_name": "Demo User",
264
264
  "team_name": "Demo Team",
@@ -266,7 +266,7 @@ def main():
266
266
  if r.status_code == 409:
267
267
  print("already exists, logging in.")
268
268
  r = client.post("/auth/login", json={
269
- "email": "demo@evalcraft.dev",
269
+ "email": "demo@example.com",
270
270
  "password": "demodemo123",
271
271
  })
272
272
  r.raise_for_status()
@@ -382,7 +382,7 @@ def main():
382
382
 
383
383
  print()
384
384
  print("Seed complete!")
385
- print(f" Login: demo@evalcraft.dev / demodemo123")
385
+ print(f" Login: demo@example.com / demodemo123")
386
386
  print(f" Frontend: http://localhost:3000")
387
387
  print(f" Backend: http://localhost:8000")
388
388
  print(f" API docs: http://localhost:8000/docs")
@@ -140,7 +140,7 @@ def test_auth(client: httpx.Client) -> str | None:
140
140
  print(f"\n{BOLD}Auth{RESET}")
141
141
 
142
142
  unique = uuid.uuid4().hex[:8]
143
- email = f"smoke-{unique}@evalcraft.dev"
143
+ email = f"smoke-{unique}@example.com"
144
144
  password = "smoketest123"
145
145
 
146
146
  # Signup
@@ -0,0 +1 @@
1
+ # No custom domain configured.
@@ -940,7 +940,7 @@ def test_agent_output():
940
940
  <li>Weekly check-in &amp; roadmap input</li>
941
941
  <li>Migration &amp; setup help</li>
942
942
  </ul>
943
- <a href="mailto:hello@evalcraft.dev?subject=Design Partner Application&body=Hi, I'm interested in the design partner pilot.%0A%0ATeam:%0AWhat we build:%0AFramework (OpenAI/LangGraph/CrewAI/etc):%0A" class="btn btn-primary">Apply as Design Partner</a>
943
+ <a href="mailto:beyhangl@gmail.com?subject=Design Partner Application&body=Hi, I'm interested in the design partner pilot.%0A%0ATeam:%0AWhat we build:%0AFramework (OpenAI/LangGraph/CrewAI/etc):%0A" class="btn btn-primary">Apply as Design Partner</a>
944
944
  </div>
945
945
  <div class="price-card">
946
946
  <h3>Team</h3>
@@ -966,7 +966,7 @@ def test_agent_output():
966
966
  <li>Self-hosted option</li>
967
967
  <li>Dedicated support</li>
968
968
  </ul>
969
- <a href="mailto:hello@evalcraft.dev" class="btn btn-secondary">Contact us</a>
969
+ <a href="mailto:beyhangl@gmail.com" class="btn btn-secondary">Contact us</a>
970
970
  </div>
971
971
  </div>
972
972
  </div>
@@ -976,7 +976,7 @@ def test_agent_output():
976
976
  <section style="text-align:center;padding:56px 24px;background:var(--accent-glow);border-top:1px solid rgba(37,99,235,0.12);border-bottom:1px solid rgba(37,99,235,0.12);">
977
977
  <h3 style="font-size:22px;font-weight:700;margin-bottom:8px;">Looking for 10 design partners</h3>
978
978
  <p style="font-size:16px;color:var(--text-2);max-width:560px;margin:0 auto 24px;line-height:1.7;">Get hands-on onboarding, direct Slack access, and shape the roadmap. Limited to teams building AI agents in production.</p>
979
- <a href="mailto:hello@evalcraft.dev?subject=Design Partner Application&body=Hi, I'm interested in the design partner pilot.%0A%0ATeam:%0AWhat we build:%0AFramework (OpenAI/LangGraph/CrewAI/etc):%0A" class="btn btn-primary" style="font-size:16px;">Apply Now</a>
979
+ <a href="mailto:beyhangl@gmail.com?subject=Design Partner Application&body=Hi, I'm interested in the design partner pilot.%0A%0ATeam:%0AWhat we build:%0AFramework (OpenAI/LangGraph/CrewAI/etc):%0A" class="btn btn-primary" style="font-size:16px;">Apply Now</a>
980
980
  </section>
981
981
 
982
982
  <!-- ─── Star CTA ──────────────────────────────────────── -->
@@ -52,7 +52,7 @@ def golden_set(cassette):
52
52
  def client(tmp_path):
53
53
  return EvalcraftCloud(
54
54
  api_key="ec_test_key",
55
- base_url="https://api.evalcraft.dev/v1",
55
+ base_url="https://dash.example.com/v1",
56
56
  timeout=5,
57
57
  max_retries=2,
58
58
  queue_dir=tmp_path / "queue",
@@ -97,12 +97,23 @@ def test_api_key_from_config(tmp_path, monkeypatch):
97
97
  assert c.api_key == "ec_from_config"
98
98
 
99
99
 
100
+ def test_no_base_url_configured_raises_clear_error(tmp_path, monkeypatch):
101
+ """With no base_url (arg / env / config), a cloud request fails with a clear,
102
+ self-host-pointing error instead of hitting a non-existent default host."""
103
+ monkeypatch.delenv("EVALCRAFT_BASE_URL", raising=False)
104
+ with patch("evalcraft.cloud.client._CONFIG_FILE", tmp_path / "missing.json"):
105
+ c = EvalcraftCloud(api_key="ec_x", queue_dir=tmp_path / "queue")
106
+ assert c.base_url == ""
107
+ with pytest.raises(CloudUploadError, match="self-hosted"):
108
+ c.list_cassettes("proj")
109
+
110
+
100
111
  # ──────────────────────────────────────────────
101
112
  # upload()
102
113
  # ──────────────────────────────────────────────
103
114
 
104
115
  def test_upload_cassette_success(client, cassette):
105
- server_resp = {"id": "cas_abc123", "url": "https://app.evalcraft.dev/cassettes/cas_abc123"}
116
+ server_resp = {"id": "cas_abc123", "url": "https://app.example.com/cassettes/cas_abc123"}
106
117
  mock_resp = _make_mock_response(server_resp)
107
118
 
108
119
  with patch("urllib.request.urlopen", return_value=mock_resp) as mock_open:
@@ -113,7 +124,7 @@ def test_upload_cassette_success(client, cassette):
113
124
 
114
125
  # Verify correct URL and method
115
126
  req = mock_open.call_args[0][0]
116
- assert req.full_url == "https://api.evalcraft.dev/v1/cassettes"
127
+ assert req.full_url == "https://dash.example.com/v1/cassettes"
117
128
  assert req.method == "POST"
118
129
  assert req.headers.get("Authorization") == "Bearer ec_test_key"
119
130
  assert req.headers.get("Content-type") == "application/json"
@@ -142,7 +153,7 @@ def test_upload_cassette_queued_on_failure(client, cassette, tmp_path):
142
153
  # ──────────────────────────────────────────────
143
154
 
144
155
  def test_upload_golden_success(client, golden_set):
145
- server_resp = {"id": "gs_xyz", "url": "https://app.evalcraft.dev/golden/gs_xyz"}
156
+ server_resp = {"id": "gs_xyz", "url": "https://app.example.com/golden/gs_xyz"}
146
157
  mock_resp = _make_mock_response(server_resp)
147
158
 
148
159
  with patch("urllib.request.urlopen", return_value=mock_resp) as mock_open:
@@ -150,7 +161,7 @@ def test_upload_golden_success(client, golden_set):
150
161
 
151
162
  assert result["id"] == "gs_xyz"
152
163
  req = mock_open.call_args[0][0]
153
- assert req.full_url == "https://api.evalcraft.dev/v1/golden-sets"
164
+ assert req.full_url == "https://dash.example.com/v1/golden-sets"
154
165
  payload = json.loads(req.data.decode("utf-8"))
155
166
  assert payload["name"] == "weather_golden"
156
167
 
@@ -203,7 +214,7 @@ def test_get_regressions(client):
203
214
  def test_retry_on_5xx_then_success(client, cassette):
204
215
  """Should retry on 5xx and succeed on the next attempt."""
205
216
  server_err = urllib.error.HTTPError(
206
- url="https://api.evalcraft.dev/v1/cassettes",
217
+ url="https://dash.example.com/v1/cassettes",
207
218
  code=503,
208
219
  msg="Service Unavailable",
209
220
  hdrs=MagicMock(), # type: ignore[arg-type]
@@ -221,7 +232,7 @@ def test_retry_on_5xx_then_success(client, cassette):
221
232
  def test_no_retry_on_4xx(client, cassette):
222
233
  """4xx errors should not be retried."""
223
234
  err = urllib.error.HTTPError(
224
- url="https://api.evalcraft.dev/v1/cassettes",
235
+ url="https://dash.example.com/v1/cassettes",
225
236
  code=401,
226
237
  msg="Unauthorized",
227
238
  hdrs=MagicMock(), # type: ignore[arg-type]
@@ -76,7 +76,7 @@ class TestE2ECapture:
76
76
 
77
77
  # Verify JSON is valid and contains expected data
78
78
  data = json.loads(cassette_path.read_text())
79
- assert data.get("evalcraft_version") == "0.2.0"
79
+ assert data.get("evalcraft_version") == "0.2.1"
80
80
  assert data["cassette"]["name"] == "weather_agent_run"
81
81
  assert data["cassette"]["agent_name"] == "weather_bot"
82
82
  assert data["cassette"]["framework"] == "openai"
@@ -1 +0,0 @@
1
- # Add custom domain here: evalcraft.dev
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