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.
- {evalcraft-0.2.0 → evalcraft-0.2.1}/CHANGELOG.md +5 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/PKG-INFO +1 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/__init__.py +1 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/main.py +3 -3
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/evalcraft.toml +1 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cloud/client.py +31 -14
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/core/models.py +1 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/pyproject.toml +1 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/seed_demo.py +3 -3
- {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/smoke_test.py +1 -1
- evalcraft-0.2.1/site/CNAME +1 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/site/index.html +3 -3
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_cloud.py +18 -7
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_e2e_pipeline.py +1 -1
- evalcraft-0.2.0/site/CNAME +0 -1
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.env.example +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/design-partner-feedback.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/workflows/ci.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.github/workflows/publish.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/.gitignore +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/CONTRIBUTING.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/LICENSE +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/Makefile +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/action.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/Dockerfile +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/env.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/script.py.mako +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/versions/.gitkeep +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic/versions/001_initial.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/alembic.ini +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/auth.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/cassettes.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/golden_sets.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/projects.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/regressions.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/api/webhooks.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/cache.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/config.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/database.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/logging_config.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/main.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/cassette.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/golden_set.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/project.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/regression.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/models/user.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/schemas/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/schemas/api.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/alert_service.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/analytics_service.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/cassette_service.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/app/services/regression_service.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/entrypoint.sh +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/conftest.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_auth.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_cassettes.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_golden_sets.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_projects.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_regressions.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/backend/tests/test_webhooks.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/.gitignore +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/Dockerfile +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/eslint.config.js +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/index.html +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/nginx.conf +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/package-lock.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/package.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/public/vite.svg +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/App.css +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/App.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/ErrorBoundary.test.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/Skeleton.test.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/__tests__/api.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/assets/react.svg +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateGoldenSetModal.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateProjectModal.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/ErrorBoundary.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Layout.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/MetricCard.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Sidebar.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Skeleton.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/StatusBadge.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/Toast.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/UploadCassetteModal.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/context/AuthContext.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/hooks/useApi.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/index.css +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/main.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Analytics.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/CassetteDetail.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Cassettes.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Dashboard.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/GoldenSetDetail.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/GoldenSets.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Login.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Regressions.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/pages/Settings.tsx +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/services/api.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/test-setup.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.app.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/tsconfig.node.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/vite.config.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/vitest.config.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docker-compose.production.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docker-compose.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/index.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/logo.png +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/anthropic.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/crewai.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/langgraph.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/adapters/openai.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/capture.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/changelog.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/ci-cd.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/cli.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/concepts.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/five-minute-case-study.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/index.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/live-eval.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/mock.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/pytest-plugin.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/quickstart.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/replay.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/docs/user-guide/scorers.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/anthropic_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/autogen_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/crewai_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/gemini_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/langgraph_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/llamaindex_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/openai_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/adapters/pydantic_ai_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/email.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/slack.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/alerts/webhook.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/capture/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/capture/recorder.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/doctor_cmd.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/generate_cmd.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/init_cmd.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/conftest.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_anthropic.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_crewai.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_generic.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_langgraph.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cli/templates/test_agent_openai.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/cloud/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/core/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/_utils.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/hallucination.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/judge_cache.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/jury.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/live.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/llm_judge.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/pairwise.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/rag_scorers.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/scorers/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/eval/statistical.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/golden/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/golden/manager.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/llm.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/mock/tool.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/pytest_plugin/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/pytest_plugin/plugin.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/detector.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/regression/trend.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/engine.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/replay/network_guard.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/sanitize/__init__.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/evalcraft/sanitize/redactor.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/agent.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/record_cassettes.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/cassettes/auth_middleware_review.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/cassettes/db_pool_refactor_review.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/anthropic-agent/tests/test_code_review_agent.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/basic_capture.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/.github/workflows/eval.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/evalcraft-ci.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/evalcraft_gate.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/ci-pipeline/tests/test_ci_gate.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/example-ci-gate.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/record_cassettes.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/cassettes/equipment_stipend.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/cassettes/remote_work_policy.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/tests/test_rag_workflow.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/langgraph-workflow/workflow.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/README.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/agent.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/build_golden.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/record_cassettes.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/damaged_item.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/order_tracking.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/cassettes/return_request.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/test_golden.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/openai-agent/tests/test_support_agent.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/replay_and_diff.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/examples/test_with_mocks.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/dm-templates.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/outreach-targets.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/outreach-tracker.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/reddit-langchain.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/reddit-python.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/show-hn.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/tracking-dashboard.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch/twitter-thread.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/launch-posts.md +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/mkdocs.yml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/package-lock.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/package.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/gemini.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/openai.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/adapters/vercel-ai.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/capture/recorder.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/core/models.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/core/types.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/llm-judge.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/rag-scorers.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/eval/scorers.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/index.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/mock/llm.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/mock/tool.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/replay/engine.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/src/types/externals.d.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/capture.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/mock.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/models.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/replay.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/scorers.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tests/vercel-ai.test.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/tsconfig.json +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/packages/evalcraft-js/vitest.config.ts +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/requirements.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/scripts/validate_with_openai.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/site/logo.png +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/site/robots.txt +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/site/sitemap.xml +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/site/thank-you.html +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/conftest.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/regression/test_trend_detector.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_alerts.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_anthropic_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_doctor.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_gemini_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_generate_tests.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_golden.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_hallucination.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_init.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_judge_cache.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_jury.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_live_eval.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_llm_judge.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_mock_llm.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_mock_tool.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_models.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_network_guard.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_pairwise.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_provenance.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_pydantic_ai_adapter.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_rag_scorers.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_recorder.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_regression.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_replay.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_sanitize.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_scorer_offline.py +0 -0
- {evalcraft-0.2.0 → evalcraft-0.2.1}/tests/test_scorers.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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="
|
|
1115
|
-
help="
|
|
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
|
|
|
@@ -34,13 +34,11 @@ from typing import Any
|
|
|
34
34
|
|
|
35
35
|
logger = logging.getLogger(__name__)
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
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:
|
|
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 =
|
|
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 =
|
|
241
|
-
"""Persist API key and
|
|
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
|
-
|
|
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.
|
|
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}"
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "evalcraft"
|
|
7
|
-
version = "0.2.
|
|
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@
|
|
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@
|
|
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@
|
|
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}@
|
|
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 & roadmap input</li>
|
|
941
941
|
<li>Migration & setup help</li>
|
|
942
942
|
</ul>
|
|
943
|
-
<a href="mailto:
|
|
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:
|
|
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:
|
|
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://
|
|
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.
|
|
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://
|
|
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.
|
|
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://
|
|
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://
|
|
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://
|
|
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.
|
|
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"
|
evalcraft-0.2.0/site/CNAME
DELETED
|
@@ -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
|
|
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
|
|
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
|
{evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateGoldenSetModal.tsx
RENAMED
|
File without changes
|
{evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/CreateProjectModal.tsx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{evalcraft-0.2.0 → evalcraft-0.2.1}/dashboard/frontend/src/components/UploadCassetteModal.tsx
RENAMED
|
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
|