Coverage for src / lexigram / contracts / ai / index.py: 0%
35 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-15 18:57 +0800
1"""Index and query engine protocols for RAG."""
3from __future__ import annotations
5from collections.abc import AsyncIterator
6from dataclasses import dataclass, field
7from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
9if TYPE_CHECKING:
10 from lexigram.contracts.ai.vector import Document
11 from lexigram.contracts.core.result import Result
13from lexigram.contracts.ai.exceptions import RAGError
16class IndexError(RAGError): # noqa: A001
17 """Raised when index operations fail in an expected, recoverable way."""
19 _code = "LEX_ERR_IDX_001"
21 def __init__(self, message: str = "Index error", **kwargs: Any) -> None:
22 super().__init__(message, **kwargs)
25class QueryEngineError(RAGError):
26 """Raised when query engine operations fail in an expected, recoverable way."""
28 _code = "LEX_ERR_QE_001"
30 def __init__(self, message: str = "Query engine error", **kwargs: Any) -> None:
31 super().__init__(message, **kwargs)
34@dataclass(frozen=True)
35class Citation:
36 """A citation linking an answer fragment to a source node.
38 Attributes:
39 node_id: Unique identifier of the source node.
40 text: The cited text content.
41 score: Relevance score of the citation.
42 """
44 node_id: str
45 text: str
46 score: float
49@dataclass(frozen=True)
50class QueryEngineResponse:
51 """Response from a query engine.
53 Attributes:
54 answer: The generated answer text.
55 source_nodes: List of source nodes used in generation.
56 citations: List of citations linking answer to sources.
57 tokens: Total tokens used (if available, otherwise 0).
58 cost: Total cost in USD (if available, otherwise 0.0).
59 """
61 answer: str
62 source_nodes: list[Any] = field(default_factory=list)
63 citations: list[Citation] = field(default_factory=list)
64 tokens: int = 0
65 cost: float = 0.0
68@runtime_checkable
69class IndexProtocol(Protocol):
70 """Protocol for document indices.
72 Implementations store embedded documents and provide search capabilities.
73 """
75 async def insert(self, documents: list[Document]) -> Result[list[str], IndexError]:
76 """Insert documents into the index.
78 Args:
79 documents: List of documents to insert.
81 Returns:
82 Ok(list of document IDs) on success.
83 Err(IndexError) on failure.
84 """
85 ...
87 async def delete(self, ids: list[str]) -> Result[int, IndexError]:
88 """Delete documents by ID.
90 Args:
91 ids: List of document IDs to delete.
93 Returns:
94 Ok(count of deleted documents) on success.
95 Err(IndexError) on failure.
96 """
97 ...
99 def as_retriever(self, **kwargs: Any) -> Any:
100 """Convert this index to a retriever.
102 Args:
103 **kwargs: Retriever-specific parameters (top_k, filters, etc.).
105 Returns:
106 A retriever instance.
107 """
108 ...
111@runtime_checkable
112class QueryEngineProtocol(Protocol):
113 """Protocol for query engines.
115 Implementations process user queries and return answers with sources.
116 """
118 async def query(
119 self, query: str, **kwargs: Any
120 ) -> Result[QueryEngineResponse, QueryEngineError]:
121 """Process a query and return an answer with sources.
123 Args:
124 query: The user's query string.
125 **kwargs: Query-specific parameters.
127 Returns:
128 Ok(QueryEngineResponse) on success.
129 Err(QueryEngineError) on failure.
130 """
131 ...
133 async def astream_query(
134 self, query: str, **kwargs: Any
135 ) -> AsyncIterator[Result[QueryEngineResponse, QueryEngineError]]:
136 """Stream query results.
138 Args:
139 query: The user's query string.
140 **kwargs: Query-specific parameters.
142 Yields:
143 Result containing partial QueryEngineResponse or error.
144 """
145 ...
148__all__ = [
149 "Citation",
150 "IndexError",
151 "IndexProtocol",
152 "QueryEngineError",
153 "QueryEngineProtocol",
154 "QueryEngineResponse",
155]