Skip to content

Commit de0494c

Browse files
committed
feat: add plugins, error hierarchy, vector search connector, and server fixes
Signed-off-by: Arseny Kravchenko <[email protected]>
1 parent 29febc1 commit de0494c

27 files changed

+4771
-68
lines changed

packages/appkit-rs/appkit.pyi

Lines changed: 205 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,22 @@ class Plugin:
208208
phase: str = "normal",
209209
manifest: PluginManifest,
210210
) -> None: ...
211-
def setup(self) -> Awaitable[None]: ...
212-
def exports(self) -> dict[str, str]: ...
213-
def client_config(self) -> dict[str, str]: ...
214-
def inject_routes(self, router: Router) -> None: ...
211+
def setup(self) -> Awaitable[None]:
212+
"""One-time initialization hook called once during
213+
:meth:`AppKit.initialize` after the plugin's runtime is injected.
214+
"""
215+
...
216+
def exports(self) -> dict[str, str]:
217+
"""Return string values exported to other plugins and the server."""
218+
...
219+
def client_config(self) -> dict[str, str]:
220+
"""Return per-plugin config surfaced to clients via ``/api/config``."""
221+
...
222+
def inject_routes(self, router: Router) -> None:
223+
"""Register HTTP routes with the server router. Called once per
224+
plugin, mounted under ``/api/<plugin-name>/``.
225+
"""
226+
...
215227
def execute(
216228
self,
217229
func: Callable[[], Awaitable[str]],
@@ -221,7 +233,16 @@ class Plugin:
221233
retry_attempts: Optional[int] = None,
222234
cache_key: Optional[list[str]] = None,
223235
cache_ttl: Optional[int] = None,
224-
) -> Awaitable[ExecutionResult]: ...
236+
) -> Awaitable[ExecutionResult]:
237+
"""Execute a coroutine through the plugin's interceptor chain
238+
(telemetry, timeout, retry, cache).
239+
240+
``user_key`` scopes caches to a user for OBO flows. ``cache_key``
241+
parts are hashed together with ``user_key`` to form a stable key.
242+
Pass ``timeout_ms=None`` / ``retry_attempts=None`` to fall back to
243+
the plugin defaults.
244+
"""
245+
...
225246
def execute_stream(
226247
self,
227248
func: Callable[[], Any],
@@ -240,20 +261,45 @@ class Plugin:
240261
def __repr__(self) -> str: ...
241262

242263
class AppKit:
243-
"""AppKit orchestrator — registers plugins and manages initialization."""
264+
"""AppKit orchestrator — registers plugins and manages initialization.
265+
266+
Most applications should use :func:`create_app` instead of driving
267+
this class directly; ``create_app`` wires registration, initialization
268+
and optional server startup in one call.
269+
"""
244270

245271
def __init__(self) -> None: ...
246-
def register(self, plugin: Plugin) -> None: ...
272+
def register(self, plugin: Plugin) -> None:
273+
"""Register a plugin. Must be called before :meth:`initialize`."""
274+
...
247275
def initialize(
248276
self,
249277
config: AppConfig,
250278
*,
251279
cache_config: Optional[CacheConfig] = None,
252-
) -> Awaitable[None]: ...
253-
def get_plugin(self, name: str) -> Optional[Plugin]: ...
254-
def plugin_names(self) -> list[str]: ...
255-
def start_server(self, server_config: ServerConfig) -> Awaitable[None]: ...
256-
def shutdown(self) -> None: ...
280+
) -> Awaitable[None]:
281+
"""Initialize telemetry, cache, and run phase-ordered ``Plugin.setup``.
282+
283+
After this returns, plugins are ready to serve requests. Calling
284+
``initialize`` twice is an error.
285+
"""
286+
...
287+
def get_plugin(self, name: str) -> Optional[Plugin]:
288+
"""Look up a registered plugin by its manifest name."""
289+
...
290+
def plugin_names(self) -> list[str]:
291+
"""Return the manifest names of all registered plugins."""
292+
...
293+
def start_server(self, server_config: ServerConfig) -> Awaitable[None]:
294+
"""Start the HTTP server and block until it exits.
295+
296+
Routes previously injected via ``Plugin.inject_routes`` are mounted
297+
under ``/api/<plugin-name>/...``.
298+
"""
299+
...
300+
def shutdown(self) -> None:
301+
"""Stop the HTTP server and release resources."""
302+
...
257303
def __repr__(self) -> str: ...
258304
def __len__(self) -> int: ...
259305
def __bool__(self) -> bool: ...
@@ -381,43 +427,71 @@ class FilePreview:
381427
def __repr__(self) -> str: ...
382428

383429
class FilesConnector:
384-
"""Databricks Files API connector."""
430+
"""Databricks Files API connector.
431+
432+
Operates against Unity Catalog Volume paths. The ``default_volume``
433+
constructor argument is used as a prefix when a ``file_path`` is not
434+
already a ``/Volumes/...`` absolute path.
435+
"""
385436

386437
def __init__(self, host: str, *, default_volume: Optional[str] = None) -> None: ...
387-
def resolve_path(self, file_path: str) -> str: ...
438+
def resolve_path(self, file_path: str) -> str:
439+
"""Join ``file_path`` with the connector's default volume if the
440+
path is not already a fully-qualified ``/Volumes/...`` path.
441+
"""
442+
...
388443
def list(
389444
self,
390445
token: str,
391446
*,
392447
directory_path: Optional[str] = None,
393-
) -> Awaitable[list[FileDirectoryEntry]]: ...
448+
) -> Awaitable[list[FileDirectoryEntry]]:
449+
"""List entries under ``directory_path`` (or the default volume)."""
450+
...
394451
def read(
395452
self,
396453
token: str,
397454
file_path: str,
398455
*,
399456
max_size: Optional[int] = None,
400-
) -> Awaitable[str]: ...
401-
def download(self, token: str, file_path: str) -> Awaitable[bytes]: ...
402-
def exists(self, token: str, file_path: str) -> Awaitable[bool]: ...
403-
def metadata(self, token: str, file_path: str) -> Awaitable[FileMetadata]: ...
457+
) -> Awaitable[str]:
458+
"""Read a text file, optionally truncated to ``max_size`` bytes."""
459+
...
460+
def download(self, token: str, file_path: str) -> Awaitable[bytes]:
461+
"""Download a file as raw bytes."""
462+
...
463+
def exists(self, token: str, file_path: str) -> Awaitable[bool]:
464+
"""Return whether the given file or directory exists."""
465+
...
466+
def metadata(self, token: str, file_path: str) -> Awaitable[FileMetadata]:
467+
"""Fetch metadata for a file via a HEAD request."""
468+
...
404469
def upload(
405470
self,
406471
token: str,
407472
file_path: str,
408473
contents: bytes,
409474
*,
410475
overwrite: bool = True,
411-
) -> Awaitable[None]: ...
412-
def create_directory(self, token: str, directory_path: str) -> Awaitable[None]: ...
413-
def delete(self, token: str, file_path: str) -> Awaitable[None]: ...
476+
) -> Awaitable[None]:
477+
"""Upload ``contents`` to ``file_path``. Overwrites by default."""
478+
...
479+
def create_directory(self, token: str, directory_path: str) -> Awaitable[None]:
480+
"""Create a directory, creating parents as needed."""
481+
...
482+
def delete(self, token: str, file_path: str) -> Awaitable[None]:
483+
"""Delete a file or (empty) directory."""
484+
...
414485
def preview(
415486
self,
416487
token: str,
417488
file_path: str,
418489
*,
419490
max_chars: int = 1024,
420-
) -> Awaitable[FilePreview]: ...
491+
) -> Awaitable[FilePreview]:
492+
"""Fetch metadata and a capped-length text preview if the file is
493+
recognized as text."""
494+
...
421495
def __repr__(self) -> str: ...
422496

423497
# ---------------------------------------------------------------------------
@@ -448,7 +522,12 @@ class SqlStatementResult:
448522
def __bool__(self) -> bool: ...
449523

450524
class SqlWarehouseConnector:
451-
"""Databricks SQL Warehouse connector."""
525+
"""Databricks SQL Warehouse connector.
526+
527+
Runs parameterised SQL statements against a Serverless or Pro warehouse
528+
via the ``/api/2.0/sql/statements`` endpoint and polls until the
529+
statement reaches a terminal status.
530+
"""
452531

453532
def __init__(self, host: str, *, timeout_ms: Optional[int] = None) -> None: ...
454533
def execute_statement(
@@ -467,7 +546,14 @@ class SqlWarehouseConnector:
467546
byte_limit: Optional[int] = None,
468547
row_limit: Optional[int] = None,
469548
timeout_ms: Optional[int] = None,
470-
) -> Awaitable[SqlStatementResult]: ...
549+
) -> Awaitable[SqlStatementResult]:
550+
"""Execute ``statement`` on ``warehouse_id`` and return the result.
551+
552+
``parameters`` is a list of ``(name, value)`` pairs corresponding
553+
to ``:name`` placeholders in the SQL; values are always passed as
554+
strings and typed by the server via column metadata.
555+
"""
556+
...
471557
def __repr__(self) -> str: ...
472558

473559
# ---------------------------------------------------------------------------
@@ -594,15 +680,22 @@ class ServingResponse:
594680
def __hash__(self) -> int: ...
595681

596682
class ServingConnector:
597-
"""Databricks Serving Endpoints connector."""
683+
"""Databricks Serving Endpoints connector.
684+
685+
Wraps ``/serving-endpoints/<name>/invocations`` for synchronous calls
686+
and the SSE streaming variant for LLM-style endpoints.
687+
"""
598688

599689
def __init__(self, host: str) -> None: ...
600690
def invoke(
601691
self,
602692
token: str,
603693
endpoint_name: str,
604694
body: str,
605-
) -> Awaitable[ServingResponse]: ...
695+
) -> Awaitable[ServingResponse]:
696+
"""Invoke a serving endpoint with a JSON request body and return
697+
the raw response."""
698+
...
606699
def stream(
607700
self,
608701
token: str,
@@ -656,7 +749,11 @@ class LakebasePgConfig:
656749
def __hash__(self) -> int: ...
657750

658751
class LakebaseConnector:
659-
"""Databricks Lakebase connector."""
752+
"""Databricks Lakebase connector.
753+
754+
Generates short-lived PostgreSQL credentials for a set of Lakebase
755+
instances via the database credentials API.
756+
"""
660757

661758
def __init__(self, host: str) -> None: ...
662759
def generate_credential(
@@ -665,7 +762,86 @@ class LakebaseConnector:
665762
instance_names: list[str],
666763
*,
667764
request_id: Optional[str] = None,
668-
) -> Awaitable[DatabaseCredential]: ...
765+
) -> Awaitable[DatabaseCredential]:
766+
"""Generate a credential good for one or more Lakebase instances.
767+
768+
Use the returned token as the PostgreSQL password for the life of
769+
``expiration_time`` — typically tens of minutes.
770+
"""
771+
...
772+
def __repr__(self) -> str: ...
773+
774+
# ---------------------------------------------------------------------------
775+
# Connectors — Vector Search
776+
# ---------------------------------------------------------------------------
777+
778+
class VsSearchRequest:
779+
"""Parsed Vector Search request matching the TS ``SearchRequest`` shape.
780+
781+
Parameters are passed by keyword; ``filters_json`` is a JSON object
782+
string of scalar-or-array filter values.
783+
"""
784+
785+
query_text: Optional[str]
786+
query_vector: Optional[list[float]]
787+
columns: Optional[list[str]]
788+
num_results: Optional[int]
789+
query_type: Optional[str]
790+
filters_json: Optional[str]
791+
reranker_columns: Optional[list[str]]
792+
793+
def __init__(
794+
self,
795+
*,
796+
query_text: Optional[str] = None,
797+
query_vector: Optional[list[float]] = None,
798+
columns: Optional[list[str]] = None,
799+
num_results: Optional[int] = None,
800+
query_type: Optional[str] = None,
801+
filters_json: Optional[str] = None,
802+
reranker_columns: Optional[list[str]] = None,
803+
) -> None: ...
804+
def __repr__(self) -> str: ...
805+
806+
class VectorSearchConnector:
807+
"""Databricks Vector Search REST connector.
808+
809+
Wraps the ``/api/2.0/vector-search`` endpoints; returns raw JSON response
810+
bodies as strings so Python callers can reuse their existing shaping
811+
logic without a second serde pass across the PyO3 boundary.
812+
"""
813+
814+
def __init__(self, host: str, *, timeout_ms: Optional[int] = None) -> None: ...
815+
def query(
816+
self,
817+
token: str,
818+
index_name: str,
819+
*,
820+
columns: list[str],
821+
num_results: int = 20,
822+
query_type: str = "hybrid",
823+
query_text: Optional[str] = None,
824+
query_vector: Optional[list[float]] = None,
825+
filters_json: Optional[str] = None,
826+
reranker_columns: Optional[list[str]] = None,
827+
) -> Awaitable[str]:
828+
"""Run a query against ``index_name`` and return the raw JSON
829+
response body.
830+
831+
Pass ``query_text`` for text/hybrid queries, ``query_vector`` for
832+
ANN queries. ``filters_json`` is the JSON-serialised filter object.
833+
"""
834+
...
835+
def query_next_page(
836+
self,
837+
token: str,
838+
index_name: str,
839+
endpoint_name: str,
840+
page_token: str,
841+
) -> Awaitable[str]:
842+
"""Fetch the next page of a paginated query using ``page_token``
843+
from a prior :meth:`query` response."""
844+
...
669845
def __repr__(self) -> str: ...
670846

671847
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)