Skip to content

Release v2.6.0: Answer API, Speakeasy removal, flattened API surface - #31

Closed
tyler5673 wants to merge 20 commits into
mainfrom
release/v2.6.0
Closed

Release v2.6.0: Answer API, Speakeasy removal, flattened API surface#31
tyler5673 wants to merge 20 commits into
mainfrom
release/v2.6.0

Conversation

@tyler5673

@tyler5673 tyler5673 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Major release with four themes: new Answer API, complete Speakeasy removal, flattened API surface, and drift detection.

New Features

  • Answer API: you.answer() / you.answer_async() for POST /v1/answer on api.you.com. Returns synthesized markdown answers with inline citations, a citations array (source URLs + excerpts), and web results. Accepts query, 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).
  • 422/500 error models expanded: UnprocessableEntityResponseErrorData now includes optional detail (FastAPI) and errors (JSON:API) fields. InternalServerErrorResponseData adds optional errors field. Backward compatible.
  • SDK drift check (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

  • Agents API fully removed: you.agents(), you.agents_async(), you.agents.runs sub-SDK shim, and all agent model/error classes deleted. No agent-related code remains in src/ or docs/.
  • search_helpers module removed: Use you.search(query=...) directly.
  • you.search_post() alias removed: Use you.search().
  • Sub-SDK deprecation: you.search.unified() and you.contents.generate() still work via backward-compat shims but emit DeprecationWarning. Preferred: you.search() and you.contents().

Speakeasy Removal

  • All "Code generated by Speakeasy — DO NOT EDIT" disclaimers removed.
  • __gen_version__ / SPEAKEASY_GENERATOR_VERSION exports removed.
  • YDCUserAgentOverrideHook deleted; __user_agent__ derived from __version__.
  • _hooks/registration.py (no-op init_hooks) deleted.
  • overlays/python_overlay.yaml deleted.
  • .speakeasy/ entries removed from .gitignore.
  • All Speakeasy/overlay references cleaned from CHANGELOG, MIGRATION, tests, and examples.

Security

  • Debug logging redaction: _redact_headers() in basesdk.py redacts Authorization, X-API-Key, Cookie, Set-Cookie before logging. Applied to both sync and async paths.
  • Empty api_key_auth opt-out: Explicit empty string constructs Security(api_key_auth=None) instead of falling back to env vars, preventing confused-deputy behavior.

Bug Fixes

  • SDKConfiguration.retry_config: Fixed pydantic.Field to dataclasses.field (stdlib @dataclass does not interpret FieldInfo).
  • _populate_from_globals: Fixed is not to != for string comparison (identity check could silently fail depending on interning).

Dead Code Cleanup

  • 25+ dead agent model files deleted (22 model .py + 3 error .py).
  • 36+ orphaned doc files deleted.
  • 21+ dead Go files deleted (handlers + model files for agents and GET /v1/search).
  • models/__init__.py and errors/__init__.py exports cleaned up.
  • _shims.py: hoisted duplicated _split_csv to module level.
  • .agents/skills/generate-sdk-and-open-pr/SKILL.md deleted (stale Speakeasy generation workflow).

CI Improvements

  • Mock server health check fixed (hits /_mockserver/health with retry loop instead of broken curl -sf /).
  • Removed -x flag so CI shows all failures, not just the first.
  • Performance tests excluded from CI unit test run.
  • Drift check runs as non-blocking step on every PR.

Test Coverage

  • 154 unit + mock server tests pass (including 4 new Answer API mock server tests).
  • 29 performance tests pass.
  • 22+ live tests pass (search, contents, answer, research, finance research, background mode).
  • mypy clean (80 source files, down from 105 after dead code removal).
  • All 5 API endpoints have Go mock server routes: search, contents, answer, research, finance_research.

@tyler5673
tyler5673 force-pushed the release/v2.6.0 branch 5 times, most recently from 39b1c45 to 5eb0872 Compare August 5, 2026 21:43
Comment thread README.md
Comment thread MIGRATION.md
Comment thread README.md Outdated
Comment thread docs/sdks/contentssdk/README.md
Comment thread src/youdotcom/basesdk.py
### 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>
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
Comment thread src/youdotcom/models/financeresearcheffort.py
Comment thread MIGRATION.md Outdated
Comment thread CONTRIBUTING.md Outdated
Comment thread src/youdotcom/sdk.py
… 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>
@factory-droid

factory-droid Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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.

@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 5, 2026
…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>
@factory-droid

factory-droid Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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>
@factory-droid

factory-droid Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Droid encountered an error —— View job


Droid is reviewing code and running a security check…

tyler5673 and others added 2 commits August 5, 2026 16:12
- 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>
@factory-droid

factory-droid Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Validated 4 inline comments for this PR: one correctness issue in SDKConfiguration’s dataclass default, plus three documentation/example fixes to make the written commands runnable (tests README, performance guide parallelism, and the example script setup).

Comment thread src/youdotcom/sdkconfiguration.py Outdated
Comment thread tests/README.md
Comment thread tests/PERFORMANCE_TESTING.md
Comment thread examples/api-example-calls.py
- 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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 validation complete.

  • Validated candidates: 2/2 approved
  • Posted as a single batched review with 2 inline comments:
    1. Add explicit permissions (contents read, issues write) to .github/workflows/drift-check.yml.
    2. Use with httpx.Client(...) as client: in scripts/check_drift.py::fetch_specs() to guarantee cleanup on exceptions.

Artifacts: /home/runner/work/_temp/droid-prompts/review_validated.json (validatedAt: 2026-08-06T01:09:51Z).

@factory-droid factory-droid Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted 2 validated inline comments (workflow token permissions, httpx client cleanup).

Comment thread .github/workflows/drift-check.yml
Comment thread scripts/check_drift.py Outdated
- 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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) complete

  • Candidates: 0
  • Approved: 0
  • Rejected: 0

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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) complete.

  • Candidates: 6
  • Approved: 6
  • Rejected: 0

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.

Comment thread src/youdotcom/sdk.py
Comment thread .github/workflows/drift-check.yml Outdated
Comment thread tests/test_client.py
Comment thread tests/test_research.py
Comment thread docs/sdks/search/README.md
Comment thread src/youdotcom/models/security.py
… 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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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 server_url contract is inconsistent for search/contents defaults.

(Posted 2 inline review comments.)

Comment thread src/youdotcom/sdk.py
Comment thread src/youdotcom/sdk.py
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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) results

  • Approved: 1
  • Rejected: 0

Overall this release PR looks cohesive, and the only remaining issue I found is a docs/type mismatch for Finance Research effort levels. FinanceResearchEffort dropped lite, but several Finance Research docstrings still advertise it as a valid research_effort value.

Comment thread src/youdotcom/models/financeresearcheffort.py
tyler5673 and others added 2 commits August 5, 2026 20:57
- 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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) complete

  • Candidates: 0
  • Approved: 0
  • Rejected: 0

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: /home/runner/work/_temp/droid-prompts/review_validated.json (validatedAt: 2026-08-06T04:09:18Z).

@youdotcom-oss youdotcom-oss deleted a comment from factory-droid Bot Aug 6, 2026
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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) complete

  • Candidates: 0
  • Approved: 0
  • Rejected: 0

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>
@factory-droid

factory-droid Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Droid finished @tyler5673's task —— View job


Phase 2 (validator) complete

  • Candidates: 0
  • Approved: 0
  • Rejected: 0

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.

@tyler5673

Copy link
Copy Markdown
Contributor Author

Superseded by #32.

Same work, reopened on release/v3.0.0. The version was corrected from 2.6.0 to 3.0.0: this release removes the Agents API, you.search_post(), search_helpers, and the sub-SDK classes, which are breaking changes and need a major bump under the SemVer policy the CHANGELOG declares. #32 also carries the review fixes (fail-fast on an empty API key, language=None opt-out, guarded client teardown, real case normalization, typed async methods) and takes the suite from 154 to 249 tests.

@tyler5673 tyler5673 closed this Aug 6, 2026
@tyler5673
tyler5673 deleted the release/v2.6.0 branch August 6, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant