Skip to content

Conversation

@jhamon
Copy link
Collaborator

@jhamon jhamon commented Feb 3, 2026

Problem

The adapter layer lacked explicit interface definitions between generated OpenAPI models and SDK code. This made it unclear what properties and methods SDK code depends on from the OpenAPI models, reducing type safety and making refactoring more error-prone.

Without formal protocols, developers had to:

  • Rely on Any types or implicit duck typing
  • Inspect OpenAPI model implementations to understand dependencies
  • Risk breaking changes when OpenAPI models evolve

Solution

This PR adds formal Protocol interfaces that define the contract between OpenAPI models and SDK adapters. Protocols are Python's way of defining structural subtyping (similar to interfaces in other languages), enabling static type checking while maintaining flexibility.

Key Architecture Decisions

  1. Protocol-based contracts: Used Python's typing.Protocol to define explicit interfaces without requiring inheritance
  2. Minimal interfaces: Each protocol defines only the attributes/methods that adapters actually depend on
  3. Separate from implementations: Protocols live in their own module, keeping concerns separated
  4. Backwards compatible: No changes to public API or runtime behavior

Protocols Added

Five protocols were created in pinecone/adapters/protocols.py:

  • QueryResponseAdapter: Interface for OpenAPI QueryResponse objects
  • UpsertResponseAdapter: Interface for OpenAPI UpsertResponse objects
  • FetchResponseAdapter: Interface for OpenAPI FetchResponse objects
  • IndexModelAdapter: Interface for OpenAPI IndexModel objects
  • IndexStatusAdapter: Interface for IndexModelStatus objects

Usage Example

The protocols enable better type safety in adapter functions:

from pinecone.adapters.protocols import QueryResponseAdapter
from pinecone.adapters import adapt_query_response

# Adapter functions now have explicit protocol types
def adapt_query_response(openapi_response: QueryResponseAdapter) -> QueryResponse:
    """Adapt an OpenAPI QueryResponse to the SDK QueryResponse dataclass.
    
    The protocol ensures openapi_response has the required attributes:
    - matches: list[ScoredVector]
    - namespace: str | None
    - usage: Usage | None
    - _data_store: dict[str, Any]
    - _response_info: Any
    """
    # Implementation remains unchanged
    return QueryResponse(
        matches=openapi_response.matches,
        namespace=openapi_response.namespace or "",
        usage=openapi_response.usage,
        _response_info=extract_response_metadata(openapi_response)
    )

For SDK users, nothing changes. The adapter functions work exactly as before:

from pinecone import Pinecone

pc = Pinecone(api_key="your-api-key")
index = pc.Index("your-index")

# Query operations work the same way
results = index.query(
    vector=[0.1, 0.2, 0.3],
    top_k=10
)

# The adapter layer uses protocols internally for type safety
# but this is transparent to end users
print(f"Found {len(results.matches)} matches")

Breaking Changes

None. This is a non-breaking internal improvement.

  • No changes to public API
  • No changes to runtime behavior
  • All existing code continues to work

Testing

Unit Tests

  • 13 new tests in tests/unit/adapters/test_protocols.py verify protocol compliance
  • All 28 adapter tests pass (13 new + 15 existing)
  • Tests verify that actual OpenAPI models satisfy protocol contracts

Type Safety

  • mypy validates protocol usage with no errors in adapters module
  • Static type checking now enforces adapter dependencies

Quality Checks

  • ✅ Unit tests: 28/28 passed
  • ✅ Type checking: No errors in adapters
  • ✅ Linting: All ruff checks passed
  • ✅ Formatting: All files properly formatted

Follow-up Items

None required. This is a complete, self-contained improvement.

Potential future enhancements (not required):

  • Add more protocols as other adapters are created
  • Use protocols in other SDK modules for similar type safety benefits

Related

  • Linear issue: SDK-275 - Phase 2B: Protocol Definitions for Adapter Layer
  • Related to: SDK adapter layer refactoring (Phase 2 of incremental improvements)

Documentation

The protocols are fully documented with docstrings explaining:

  • Purpose of each protocol
  • Required attributes and their types
  • How SDK code uses each protocol

Module-level documentation in pinecone/adapters/protocols.py explains the benefits and usage patterns.

Made with Cursor


Note

Medium Risk
Mostly type-safety and test additions, but it also changes adapt_fetch_response to normalize namespace=None to an empty string, which is a small runtime behavior change that could affect edge-case callers.

Overview
Adds a new pinecone.adapters.protocols module defining Protocol contracts for the OpenAPI models consumed by the adapter layer, and re-exports these protocols from pinecone.adapters.

Updates adapt_query_response, adapt_upsert_response, and adapt_fetch_response to accept protocol-typed inputs instead of Any, and normalizes fetch namespace to "" when the OpenAPI response provides None.

Introduces unit tests that assert real generated OpenAPI models satisfy the new protocols, plus a new adapter test covering the None-namespace fetch case.

Written by Cursor Bugbot for commit eb0b688. This will update automatically on new commits. Configure here.

Add formal Protocol interfaces that define the contract between OpenAPI
models and SDK adapters. This improves type safety, documentation, and
maintainability without any breaking changes.

- Created pinecone/adapters/protocols.py with 5 Protocol definitions
- Updated adapter functions to use protocol type annotations
- Added 13 unit tests verifying protocol compliance
- All tests pass, mypy validates protocol usage

Related: SDK-275
Co-authored-by: Cursor <cursoragent@cursor.com>
@jhamon jhamon added the enhancement New feature or request label Feb 3, 2026
@jhamon
Copy link
Collaborator Author

jhamon commented Feb 3, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Changed FetchResponseAdapter.namespace from `str` to `str | None` to
correctly reflect that the OpenAPI FetchResponse model marks namespace
as optional. Updated the adapter function to handle None namespace by
converting it to empty string, consistent with QueryResponse adapter.

- Updated protocol type annotation
- Added null-coalescing in adapter function
- Added test for None namespace case

Fixes Cursor Bugbot issue

Co-authored-by: Cursor <cursoragent@cursor.com>
@jhamon
Copy link
Collaborator Author

jhamon commented Feb 3, 2026

Fixed in commit eb0b688. Changed FetchResponseAdapter.namespace from str to str | None to correctly reflect the optional nature of the namespace field in the OpenAPI model. Also updated the adapter function to handle None namespace by converting to empty string, consistent with the QueryResponseAdapter pattern.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

"""

namespace: str | None
vectors: dict[str, Any]
Copy link

Choose a reason for hiding this comment

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

Protocol incorrectly marks vectors as required when API allows None

Medium Severity

The FetchResponseAdapter protocol defines vectors: dict[str, Any] as a required attribute, but the OpenAPI spec marks vectors as [optional]. If the API returns a response without vectors (or with null), the adapter code at openapi_response.vectors.items() will crash with an AttributeError. The protocol type should be dict[str, Any] | None to match the actual API contract and prompt defensive handling.

Fix in Cursor Fix in Web

@jhamon jhamon merged commit 876fdff into main Feb 3, 2026
42 of 43 checks passed
@jhamon jhamon deleted the jhamon/sdk-275-phase-2b-protocol-definitions-for-adapter-layer branch February 3, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants