Release v2.6.0: Answer API, Speakeasy removal, flattened API surface - #31
Release v2.6.0: Answer API, Speakeasy removal, flattened API surface#31tyler5673 wants to merge 20 commits into
Conversation
39b1c45 to
5eb0872
Compare
### Added - Answer API: you.answer() / you.answer_async() for POST /v1/answer. Returns synthesized markdown answers with inline citations and web results. - PaymentRequiredResponseError: first-class 402 error class for the answer API (UpgradeRequiredResponse schema). ### Changed - Flattened API surface: sub-SDK chains (you.search.unified(), you.contents.generate()) are deprecated with DeprecationWarning and delegate to new direct methods (you.search(), you.contents()). Plain strings accepted instead of enum imports for country, language, safesearch, livecrawl, freshness. - Removed all Speakeasy generated code and disclaimers. SDK is now fully hand-maintained. - Removed YDCUserAgentOverrideHook (no-op after Speakeasy removal). __user_agent__ derived from __version__ at runtime. - search_helpers module merged into you.search() direct method. - 422/500 error data models expanded with optional detail/errors fields (backward compatible). - Dev dependencies updated: mypy >=2.3.0, pylint >=4.0.0, pytest >=9.0.0, pytest-asyncio >=1.0.0. - CI: replaced pylint/pyright with mypy, excluded live tests from CI. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
5eb0872 to
75115cd
Compare
… empty api_key_auth opt-out - Fix broken MIGRATION.md anchor link (#250-to-260 → #250--260) - CONTRIBUTING.md: add --ignore=tests/test_performance.py to unit test command - Security: explicit empty api_key_auth now constructs Security(api_key_auth=None) instead of falling back to env vars (prevents confused-deputy footgun) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Changes look cohesive and prior review feedback appears addressed; I did not find additional high-confidence, inline-anchorable issues beyond existing PR comments. |
…t_live.py - Delete .agents/skills/generate-sdk-and-open-pr/SKILL.md — was a Speakeasy generation workflow, no longer relevant since SDK is hand-maintained - Remove empty .agents/ directory tree - Fix stale 'overlay-generated' comment in test_live.py Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid encountered an error —— View job Droid is reviewing code and running a security check… |
Keyless search never shipped in a release, so referencing a revert is misleading. Renamed heading and header to describe the current state without implying users experienced keyless. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid encountered an error —— View job Droid is reviewing code and running a security check… |
- Remove 'Hand-maintained additions' section from CHANGELOG 2.4.0 (references deleted registration.py, removed YDCUserAgentOverrideHook, and Speakeasy regen workflow that no longer exists) - Remove .speakeasy/ entries from .gitignore - Fix stale 'overlay' references in examples/api-example-calls.py, MIGRATION.md, tests/test_research.py - Fix stale 'reverted overlay' comment in tests/test_research.py - Fix stale 'Speakeasy regen' comment in tests/test_security_env.py - Clean up Speakeasy reference in CHANGELOG 2.4.0 Fixed section Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
The POST /v1/search endpoint was already supported in 2.5.x. The actual change is search_helpers.search() became you.search(). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Validated 4 inline comments for this PR: one correctness issue in |
- Hit /_mockserver/health (returns 200) with retry loop instead of broken 'curl -sf / || echo ready' that always printed ready - Remove -x flag so CI shows all failures, not just the first one Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid encountered an error —— View job Droid is reviewing code and running a security check… |
- scripts/check_drift.py: fetches OpenAPI specs from you.com and compares endpoints, server URLs, and enum values against the SDK surface - .github/workflows/test.yml: non-blocking drift check on every PR - .github/workflows/drift-check.yml: weekly scheduled check that opens a GitHub issue if drift is detected, closes stale issues when clean Known uncovered APIs (billing, images) and endpoints (GET /v1/search) are excluded via exception lists. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid encountered an error —— View job Droid is reviewing code and running a security check… |
- New handler: tests/mockserver/internal/handler/pathpostv1answer.go - Register route in generated_handlers.go - Add TestAnswerMockServer class with 4 tests hitting the mock server (basic, freshness, boost_domains, async) - Existing MockTransport tests retained for error case coverage - Update tests/README.md test count (19 -> 23) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 validation complete.
Artifacts: |
- drift-check.yml: add explicit permissions (contents: read, issues: write) so GITHUB_TOKEN can create/close issues in scheduled runs - check_drift.py: use context manager for httpx.Client to guarantee cleanup on exception paths Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) complete
Large, cohesive v2.6.0 release refactor with substantial SDK, CI, and docs changes. No additional high-confidence, inline-anchorable correctness or security issues found beyond existing PR discussions. |
Drift check (check_drift.py): - Add request parameter drift: compares spec request body properties against SDK method signatures - Add response schema drift: compares spec 200 response schema fields against SDK pydantic model fields - Fix resolution for request bodies - Fix array response schema handling (contents returns List[]) Real drift found and fixed: - ResearchResponse missing 'warnings' field (List[str]) per OpenAPI spec - Added to model and TypedDict, backward-compatible (Optional, defaults None) CI improvements (test.yml): - Add Python 3.11 and 3.13 to test matrix (was 3.10 + 3.12 only) - Add pytest-cov coverage reporting (--cov=youdotcom --cov-report=term-missing) - Add pylint errors-only check (non-blocking, continue-on-error) - Add package build check job (python -m build --sdist --wheel) Dependabot (.github/dependabot.yml): - Weekly checks for pip and github-actions dependency updates Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) complete.
Validated 6/6 inline candidates for this PR; the main actionable items are HTTP client lifecycle cleanup (especially for async context-manager usage and tests) plus a couple of CI/docs accuracy fixes to avoid misleading outputs. |
… drift workflow P1: You.__aexit__ now closes SDK-owned sync client too; __exit__ closes SDK-owned async client (prevents socket leaks in async-only usage) P2: Fix Security.serialize_model() optional_fields — was 'ApiKeyAuth' but actual field key is 'api_key_auth' (no alias), causing null fields to be re-introduced despite exclude_none P2: Drift workflow now distinguishes 'DRIFT DETECTED' from 'ERROR:' before opening an issue (prevents false drift issues on network failures) P2: Search docs — removed stale GET recommendation and changed UsageSnippet method from get to post P2: Document test client cleanup expectations in create_test_http_client Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Cohesive v2.6.0 refactor with a clear API split, but two correctness issues remain: sync context-manager teardown can leak the SDK-owned AsyncClient under a running event loop, and the documented global (Posted 2 inline review comments.) |
P1: Fix __exit__ async client close under running event loop — use get_running_loop() + run_coroutine_threadsafe() pattern (matching close_clients()) instead of asyncio.run() which raises RuntimeError in notebooks/async contexts P1: Clarify server_url constructor docstring — search/contents default to ydc-index.io and are not affected by the constructor server_url unless the per-method server_url argument is passed Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) results
Overall this release PR looks cohesive, and the only remaining issue I found is a docs/type mismatch for Finance Research effort levels. |
- CHANGELOG: Remove 'Search/Contents host' from Changed (was already the case in 2.5.0, not a new change in 2.6.0) - CHANGELOG: Reword 'search() server_url fix' to accurately state that constructor server_url does NOT affect search/contents (only per-method server_url is respected) - README: Fix error count from 27 to 28 (3 httpx + 25 YouError subclasses) - MIGRATION: Add note that server URL behavior was already the case in 2.5.0, documented for reference - tests/mockserver/README: Replace stale 'auto-generated code from Speakeasy' with 'hand-maintained', remove deleted pathgetv1search.go from handler list, add all current handler files - PR description: Remove 'Search/Contents host split' from Breaking Changes (was already the case in 2.5.0) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
FinanceResearchEffort no longer includes a LITE tier (only DEEP and EXHAUSTIVE per official You.com docs). Removed stale 'lite' bullet from docstrings in finance_researchop.py (2 places) and sdk.py finance_research/finance_research_async (2 places). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) complete
Large, cohesive v2.6.0 release refactor across SDK, CI, and docs. No additional high-confidence, inline-anchorable correctness or security issues found beyond existing PR discussions. Artifacts: |
P1: Fix drift-check.yml re-execution TOCTOU race — capture first run's
output once via GITHUB_ENV instead of re-running the script a second
time. Use distinct exit codes (0=no drift, 1=drift, 2=fetch error)
instead of grepping free-form stdout, eliminating the silent-loss
fallback where neither DRIFT DETECTED nor ERROR: appeared.
P1: Fix test_answer.py resource leaks — test_async_answer was creating
a real httpx.AsyncClient() (no MockTransport) that opened TCP sockets
to the mock server and was never closed. Switched to MockTransport
pattern (matching the rest of the file) with explicit try/finally
cleanup. Also added client.close() to the 3 sync mock-server tests
that were leaking create_test_http_client instances.
P2: Fix check_drift.py request param schema extraction — was using
bare schema.get('properties', {}).keys() while the response path used
_get_schema_properties() which handles oneOf/anyOf/allOf and arrays.
Unified to use _get_schema_properties for both paths. Also removed
redundant inline 'import re' in fetch_specs() (already at module level).
P2: Add upper bounds to pyproject.toml dev deps — mypy, pylint, pytest,
pytest-asyncio were unbounded across semver-major bumps. Pinned upper
bounds (<3, <5, <10, <2) so Dependabot can't float untested majors.
P3: Add failure sentinel to test.yml mock-server readiness loop — if
all 10 retries fail, the loop now exits 1 with a clear error message
instead of silently falling through to pytest.
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) complete
Phase 2 validation complete. No inline candidates to validate or post; no additional high-confidence, inline-anchorable issues found beyond existing PR discussion. |
Addresses the review findings on the v2.6.0 release PR.
Versioning:
- Bump 2.6.0 -> 3.0.0. The Agents API, `search_post()`, `search_helpers`,
and the sub-SDK classes are removed, which is breaking and needs a major
version under the SemVer policy the CHANGELOG claims to follow.
Behavior:
- An empty `api_key_auth` now raises ValueError at construction instead of
silently falling back to the environment. Every endpoint requires a key,
so `""` is never valid -- it means a key was expected and none arrived,
nearly always `os.getenv("YDC_API_KEY", "")` with the variable unset.
Falling back there ran the request under a different identity than the
code asked for. Callables are checked on first use.
- `search(language=None)` sends no language again. Omitting the argument
still uses the API default (EN); previously an explicit None also
resolved to EN, with no way to opt out of the filter.
- `__exit__`/`__aexit__` no longer let a failing client close replace the
exception propagating out of the block, matching `close_clients`.
- `country`/`language`/`safesearch`/`livecrawl`/`livecrawl_formats`/
`freshness` are now genuinely case-normalized, which the docs already
claimed. Also fixes the `to` separator in uppercase date ranges.
- `search_async()`/`contents_async()` are real methods with full
signatures instead of `**kwargs: Any` wrappers that erased them for type
checkers and IDEs. Clears the one pylint error in the tree.
Tests (154 -> 249):
- New coverage for debug-log redaction, empty-key rejection, dual client
close and its non-masking property, and the normalization matrix
including the deprecated `unified()` path. Redaction and the key
handling were both shipped untested.
Docs:
- Replace all 52 `os.getenv("YDC_API_KEY", "")` examples, which the new
key handling turns into an error.
- CHANGELOG gains Removed/Security/Fixed sections; drops an entry for a
file that never existed on main and two no-op entries. Security is now
redaction alone -- the key change is fail-fast, not a closed hole.
- MIGRATION gains an action-required table plus sections on key
resolution, client lifecycle, redaction, and `language`.
CI:
- Drift issues update an existing open issue instead of filing a duplicate
weekly; body written via --body-file so the code fence renders; a broken
checker exits 3 and fails the job rather than reporting "no drift"
forever; --strict and --verbose mean something again.
- Dev tooling installs from the pyproject dependency group instead of a
duplicated list. pylint gates now that the tree is clean. dependabot
switched pip -> uv so uv.lock actually gets updated.
Verified: 249 tests pass, mypy clean (80 files), pylint 10.00/10, drift
check green against the live specs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Droid finished @tyler5673's task —— View job Phase 2 (validator) complete
Large, cohesive 3.0.0 release refactor (Answer API, Speakeasy removal, CI/drift tooling, and agent removal). No additional high-confidence, inline-anchorable correctness or security issues found beyond existing PR discussions. |
|
Superseded by #32. Same work, reopened on |
Summary
Major release with four themes: new Answer API, complete Speakeasy removal, flattened API surface, and drift detection.
New Features
you.answer()/you.answer_async()forPOST /v1/answeronapi.you.com. Returns synthesized markdown answers with inline citations, a citations array (source URLs + excerpts), and web results. Acceptsquery,freshness,country,language,include_domains,exclude_domains,boost_domains. Country/language accept plain strings (normalized to uppercase).PaymentRequiredResponseError: New first-class error class for HTTP 402 responses with structured data (error,message,upgrade_url,limit,used,period,reset_at).UnprocessableEntityResponseErrorDatanow includes optionaldetail(FastAPI) anderrors(JSON:API) fields.InternalServerErrorResponseDataadds optionalerrorsfield. Backward compatible.scripts/check_drift.py): Fetches You.com OpenAPI specs and compares endpoints, server URLs, and enum values against the SDK surface. Runs as a non-blocking CI step on every PR and as a weekly scheduled workflow that opens an issue if drift is detected.Breaking Changes
you.agents(),you.agents_async(),you.agents.runssub-SDK shim, and all agent model/error classes deleted. No agent-related code remains insrc/ordocs/.search_helpersmodule removed: Useyou.search(query=...)directly.you.search_post()alias removed: Useyou.search().you.search.unified()andyou.contents.generate()still work via backward-compat shims but emitDeprecationWarning. Preferred:you.search()andyou.contents().Speakeasy Removal
__gen_version__/SPEAKEASY_GENERATOR_VERSIONexports removed.YDCUserAgentOverrideHookdeleted;__user_agent__derived from__version__._hooks/registration.py(no-opinit_hooks) deleted.overlays/python_overlay.yamldeleted..speakeasy/entries removed from.gitignore.Security
_redact_headers()inbasesdk.pyredactsAuthorization,X-API-Key,Cookie,Set-Cookiebefore logging. Applied to both sync and async paths.api_key_authopt-out: Explicit empty string constructsSecurity(api_key_auth=None)instead of falling back to env vars, preventing confused-deputy behavior.Bug Fixes
SDKConfiguration.retry_config: Fixedpydantic.Fieldtodataclasses.field(stdlib@dataclassdoes not interpretFieldInfo)._populate_from_globals: Fixedis notto!=for string comparison (identity check could silently fail depending on interning).Dead Code Cleanup
.py+ 3 error.py).models/__init__.pyanderrors/__init__.pyexports cleaned up._shims.py: hoisted duplicated_split_csvto module level..agents/skills/generate-sdk-and-open-pr/SKILL.mddeleted (stale Speakeasy generation workflow).CI Improvements
/_mockserver/healthwith retry loop instead of brokencurl -sf /).-xflag so CI shows all failures, not just the first.Test Coverage