From fdb32122f93ac78423784fca910faade51bac7f5 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Tue, 8 Oct 2024 14:19:08 +0200 Subject: [PATCH 01/13] Introduce files service (#2) --- examples/async/assistants/__init__.py | 0 examples/async/assistants/example_file | 1 + examples/async/assistants/files.py | 37 + pyproject.toml | 12 +- src/yandex_cloud_ml_sdk/_files/__init__.py | 0 src/yandex_cloud_ml_sdk/_files/file.py | 210 ++ src/yandex_cloud_ml_sdk/_files/resource.py | 141 ++ src/yandex_cloud_ml_sdk/_models/__init__.py | 2 +- .../_models/completions/function.py | 4 +- .../_models/text_classifiers/function.py | 4 +- .../_models/text_embeddings/function.py | 4 +- src/yandex_cloud_ml_sdk/_sdk.py | 3 + src/yandex_cloud_ml_sdk/_types/function.py | 12 +- src/yandex_cloud_ml_sdk/_types/misc.py | 9 + src/yandex_cloud_ml_sdk/_types/resource.py | 9 + src/yandex_cloud_ml_sdk/_utils/proto.py | 19 + .../cassettes/test_files/test_file.gprc.json | 558 +++++ .../cassettes/test_files/test_file.yaml | 48 + .../test_files/test_file_deleted.gprc.json | 429 ++++ .../test_files/test_file_get.gprc.json | 456 ++++ .../test_files/test_file_list.gprc.json | 1873 +++++++++++++++++ .../cassettes/test_files/test_file_list.yaml | 462 ++++ tests/assistants/test_files.py | 96 + tests/conftest.py | 10 +- tox.ini | 3 +- 25 files changed, 4385 insertions(+), 17 deletions(-) create mode 100644 examples/async/assistants/__init__.py create mode 100644 examples/async/assistants/example_file create mode 100755 examples/async/assistants/files.py create mode 100644 src/yandex_cloud_ml_sdk/_files/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_files/file.py create mode 100644 src/yandex_cloud_ml_sdk/_files/resource.py create mode 100644 src/yandex_cloud_ml_sdk/_utils/proto.py create mode 100644 tests/assistants/cassettes/test_files/test_file.gprc.json create mode 100644 tests/assistants/cassettes/test_files/test_file.yaml create mode 100644 tests/assistants/cassettes/test_files/test_file_deleted.gprc.json create mode 100644 tests/assistants/cassettes/test_files/test_file_get.gprc.json create mode 100644 tests/assistants/cassettes/test_files/test_file_list.gprc.json create mode 100644 tests/assistants/cassettes/test_files/test_file_list.yaml create mode 100644 tests/assistants/test_files.py diff --git a/examples/async/assistants/__init__.py b/examples/async/assistants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/async/assistants/example_file b/examples/async/assistants/example_file new file mode 100644 index 0000000..2580a08 --- /dev/null +++ b/examples/async/assistants/example_file @@ -0,0 +1 @@ +Some example diff --git a/examples/async/assistants/files.py b/examples/async/assistants/files.py new file mode 100755 index 0000000..6c3ddea --- /dev/null +++ b/examples/async/assistants/files.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio +import pathlib + +from yandex_cloud_ml_sdk import AsyncYCloudML + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-files': 'assistant.api.cloud.yandex.net' + } + ) + + path = pathlib.Path(__file__).parent / 'example_file' + file = await sdk.files.upload(path) + print(file) + + await file.update(name='foo') + + second = await sdk.files.get(file.id) + + print(second) + + print(await file.get_url()) + print(await file.download_as_bytes()) + + async for file in sdk.files.list(): + print(f"delete file {file}") + await file.delete() + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/pyproject.toml b/pyproject.toml index f235d93..80adf3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ requires-python = ">=3.8.1" dynamic = ["version"] dependencies = [ - "yandexcloud>=0.292.0,!=0.293", + "yandexcloud>=0.319.0", "grpcio>=1.62.0", "get-annotations", "httpx>=0.27,<1" @@ -45,7 +45,7 @@ test = [ "tox", ] langchain = [ - "langchain-core>=0.2.29" + "langchain-core>=0.2.29,<=0.2.41" ] [project.urls] @@ -90,6 +90,10 @@ pythonpath = [ "src" ] testpaths = "tests" +asyncio_default_fixture_loop_scope = "function" +filterwarnings = [ + "ignore::DeprecationWarning:pytest_pylint" +] [tool.pylint] ignore="CVS" @@ -221,6 +225,7 @@ exclude-protected= [ "_make", "_client", "_sdk", + "_folder_id", "_from_proto", "_result_type", "_proto_result_type", @@ -230,7 +235,7 @@ valid-metaclass-classmethod-first-arg="cls" [tool.pylint.'DESIGN'] max-args=10 -max-attributes=7 +max-attributes=15 max-bool-expr=5 max-branches=12 max-locals=15 @@ -239,6 +244,7 @@ max-public-methods=20 max-returns=6 max-statements=50 min-public-methods=2 +max-positional-arguments=7 [tool.pylint.'IMPORTS'] allow-wildcard-with-all="no" diff --git a/src/yandex_cloud_ml_sdk/_files/__init__.py b/src/yandex_cloud_ml_sdk/_files/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py new file mode 100644 index 0000000..434a2d6 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -0,0 +1,210 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +import functools +from asyncio import Lock +from datetime import datetime +from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar + +import httpx +from typing_extensions import Concatenate, ParamSpec, Self +from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile +from yandex.cloud.ai.files.v1.file_service_pb2 import ( + DeleteFileRequest, DeleteFileResponse, GetFileUrlRequest, GetFileUrlResponse, UpdateFileRequest +) +from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub + +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._utils.proto import proto_to_dict +from yandex_cloud_ml_sdk._utils.sync import run_sync + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._client import AsyncCloudClient + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +P = ParamSpec('P') +T = TypeVar('T') + + +def safe(method: Callable[Concatenate[BaseFile, P], Awaitable[T]]) -> Callable[Concatenate[BaseFile, P], Awaitable[T]]: + @functools.wraps(method) + async def inner(self: BaseFile, *args: P.args, **kwargs: P.kwargs) -> T: + async with self._lock: # pylint: disable=protected-access + action = method.__name__.lstrip('_') + if self._deleted: # pylint: disable=protected-access + raise ValueError(f"you can't perform an action '{action}' on file '{self.id}' because it is deleted") + + return await method(self, *args, **kwargs) + + return inner + + +@dataclasses.dataclass(frozen=True) +class BaseFile: + _sdk: BaseSDK = dataclasses.field(repr=False) + _lock: Lock = dataclasses.field(repr=False) + _deleted: bool = dataclasses.field(repr=False) + + id: str + + @property + def _client(self) -> AsyncCloudClient: + return self._sdk._client + + def _assert_not_deleted(self, action: str) -> None: + if self._deleted: + raise ValueError(f"you can't perform action '{action}' on this file because it is deleted") + + @safe + async def _get_url( + self, + *, + timeout: float = 60 + ) -> str: + request = GetFileUrlRequest(file_id=self.id) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.GetUrl, + request, + timeout=timeout, + expected_type=GetFileUrlResponse, + ) + + return response.url + + @safe + async def _update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Self: + name_ = get_defined_value(name, '') + description_ = get_defined_value(description, '') + labels_ = get_defined_value(labels, {}) + + request = UpdateFileRequest( + file_id=self.id, + name=name_, + description=description_, + labels=labels_, + ) + + for key, value in ( + ('name', name_), + ('description', description_), + ('labels', labels_) + ): + if value is not None: + request.update_mask.paths.append(key) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Update, + request, + timeout=timeout, + expected_type=ProtoFile, + ) + self._update_from_proto(response) + + return self + + @safe + async def _delete( + self, + *, + timeout: float = 60, + ) -> None: + request = DeleteFileRequest(file_id=self.id) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + await self._client.call_service( + stub.Delete, + request, + timeout=timeout, + expected_type=DeleteFileResponse, + ) + object.__setattr__(self, '_deleted', True) + + @safe + async def _download_as_bytes( + self, + *, + chunk_size: int = 32768, + timeout: float = 60 + ) -> bytes: + # I didn't invent better way to use this function without a @safe-lock + url = await self._get_url.__wrapped__(self, timeout=timeout) # type: ignore[attr-defined] + + async with httpx.AsyncClient() as client: + async with client.stream("GET", url, timeout=timeout) as response: + response.raise_for_status() + + file_bytes = b'' + async for chunk in response.aiter_bytes(chunk_size): + file_bytes += chunk + + return file_bytes + + @classmethod + def _kwargs_from_message(cls, proto: ProtoFile) -> dict[str, Any]: + fields = dataclasses.fields(cls) + data = proto_to_dict(proto) + kwargs = {} + for field in fields: + name = field.name + if name.startswith('_'): + continue + + kwargs[name] = data.get(name) + + return kwargs + + @classmethod + def from_proto(cls, *, sdk: BaseSDK, proto: ProtoFile) -> Self: + return cls( + _sdk=sdk, + _lock=Lock(), + _deleted=False, + **cls._kwargs_from_message(proto), + ) + + def _update_from_proto(self, proto: ProtoFile) -> Self: + # We want to File to be a immutable, but also we need + # to maintain a inner status after updating and such + kwargs = self._kwargs_from_message(proto) + for key, value in kwargs.items(): + object.__setattr__(self, key, value) + return self + + +@dataclasses.dataclass(frozen=True) +class RichFile(BaseFile): + name: str | None + description: str | None + mime_type: str + created_by: str + created_at: datetime + updated_by: str + updated_at: datetime + expires_at: datetime + labels: dict[str, str] | None + + +class AsyncFile(RichFile): + get_url = RichFile._get_url + update = RichFile._update + delete = RichFile._delete + download_as_bytes = RichFile._download_as_bytes + + +class File(RichFile): + get_url = run_sync(RichFile._get_url) + update = run_sync(RichFile._update) + delete = run_sync(RichFile._delete) + download_as_bytes = run_sync(RichFile._download_as_bytes) diff --git a/src/yandex_cloud_ml_sdk/_files/resource.py b/src/yandex_cloud_ml_sdk/_files/resource.py new file mode 100644 index 0000000..945273a --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_files/resource.py @@ -0,0 +1,141 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import Generic, TypeVar + +from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile +from yandex.cloud.ai.files.v1.file_service_pb2 import ( + CreateFileRequest, GetFileRequest, ListFilesRequest, ListFilesResponse +) +from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub + +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, PathLike, UndefinedOr, coerce_path, get_defined_value +from yandex_cloud_ml_sdk._types.resource import BaseResource +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .file import AsyncFile, BaseFile, File + +FileTypeT = TypeVar('FileTypeT', bound=BaseFile) + + +class BaseFiles(BaseResource, Generic[FileTypeT]): + _file_impl: type[FileTypeT] + + async def _upload_bytes( + self, + data: bytes, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> FileTypeT: + request = CreateFileRequest( + folder_id=self._folder_id, + name=get_defined_value(name, ''), + description=get_defined_value(description, ''), + mime_type=get_defined_value(mime_type, ''), + labels=get_defined_value(labels, {}), + content=data, + ) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoFile, + ) + + return self._file_impl.from_proto(proto=response, sdk=self._sdk) + + async def _upload( + self, + path: PathLike, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> FileTypeT: + path = coerce_path(path) + return await self._upload_bytes( + data=path.read_bytes(), + name=name, + description=description, + mime_type=mime_type, + labels=labels, + timeout=timeout + ) + + async def _get( + self, + file_id: str, + *, + timeout: float = 60, + ): + # TODO: we need a global per-sdk cache on file_ids to rule out + # possibility we have two Files with same ids but different fields + request = GetFileRequest(file_id=file_id) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoFile, + ) + + return self._file_impl.from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ): + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: + while True: + request = ListFilesRequest( + folder_id=self._folder_id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListFilesResponse, + ) + for file_proto in response.files: + yield self._file_impl.from_proto(proto=file_proto, sdk=self._sdk) + + if not response.files: + return + + page_token = response.next_page_token + + +class AsyncFiles(BaseFiles[AsyncFile]): + _file_impl = AsyncFile + + upload = BaseFiles._upload + upload_bytes = BaseFiles._upload_bytes + get = BaseFiles._get + list = BaseFiles._list + + +class Files(BaseFiles[File]): + _file_impl = File + + upload = run_sync(BaseFiles._upload) + upload_bytes = run_sync(BaseFiles._upload_bytes) + get = run_sync(BaseFiles._get) + list = run_sync_generator(BaseFiles._list) diff --git a/src/yandex_cloud_ml_sdk/_models/__init__.py b/src/yandex_cloud_ml_sdk/_models/__init__.py index e2b38d4..ce8c30c 100644 --- a/src/yandex_cloud_ml_sdk/_models/__init__.py +++ b/src/yandex_cloud_ml_sdk/_models/__init__.py @@ -24,7 +24,7 @@ def _init_functions(self) -> None: members: dict[str, type] = get_annotations(self.__class__, eval_str=True) for member_name, member_class in members.items(): if issubclass(member_class, BaseFunction): - function = member_class(name=member_name, sdk=self._sdk) + function = member_class(name=member_name, sdk=self._sdk, parent_resource=self) setattr(self, member_name, function) diff --git a/src/yandex_cloud_ml_sdk/_models/completions/function.py b/src/yandex_cloud_ml_sdk/_models/completions/function.py index 63a55e4..293b113 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/function.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/function.py @@ -2,12 +2,12 @@ from typing_extensions import override -from yandex_cloud_ml_sdk._types.function import BaseFunction, ModelTypeT +from yandex_cloud_ml_sdk._types.function import BaseModelFunction, ModelTypeT from .model import AsyncGPTModel, GPTModel -class BaseCompletions(BaseFunction[ModelTypeT]): +class BaseCompletions(BaseModelFunction[ModelTypeT]): @override def __call__( self, diff --git a/src/yandex_cloud_ml_sdk/_models/text_classifiers/function.py b/src/yandex_cloud_ml_sdk/_models/text_classifiers/function.py index 9f75004..bab6538 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_classifiers/function.py +++ b/src/yandex_cloud_ml_sdk/_models/text_classifiers/function.py @@ -2,12 +2,12 @@ from typing_extensions import override -from yandex_cloud_ml_sdk._types.function import BaseFunction, ModelTypeT +from yandex_cloud_ml_sdk._types.function import BaseModelFunction, ModelTypeT from .model import AsyncTextClassifiersModel, TextClassifiersModel -class BaseTextClassifiers(BaseFunction[ModelTypeT]): +class BaseTextClassifiers(BaseModelFunction[ModelTypeT]): @override def __call__( self, diff --git a/src/yandex_cloud_ml_sdk/_models/text_embeddings/function.py b/src/yandex_cloud_ml_sdk/_models/text_embeddings/function.py index 0e876f2..35f00bf 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_embeddings/function.py +++ b/src/yandex_cloud_ml_sdk/_models/text_embeddings/function.py @@ -2,12 +2,12 @@ from typing_extensions import override -from yandex_cloud_ml_sdk._types.function import BaseFunction, ModelTypeT +from yandex_cloud_ml_sdk._types.function import BaseModelFunction, ModelTypeT from .model import AsyncTextEmbeddingsModel, TextEmbeddingsModel -class BaseTextEmbeddings(BaseFunction[ModelTypeT]): +class BaseTextEmbeddings(BaseModelFunction[ModelTypeT]): _well_known_names = { 'doc': 'text-search-doc', 'query': 'text-search-query', diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 85ecec8..441dba4 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -11,6 +11,7 @@ from ._auth import BaseAuth from ._client import AsyncCloudClient +from ._files.resource import AsyncFiles, Files from ._models import AsyncModels, Models from ._retry import RetryPolicy from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined @@ -127,7 +128,9 @@ def _get_event_loop() -> asyncio.AbstractEventLoop: class AsyncYCloudML(BaseSDK): models: AsyncModels + files: AsyncFiles class YCloudML(BaseSDK): models: Models + files: Files diff --git a/src/yandex_cloud_ml_sdk/_types/function.py b/src/yandex_cloud_ml_sdk/_types/function.py index 6d1ee7a..c52f41b 100644 --- a/src/yandex_cloud_ml_sdk/_types/function.py +++ b/src/yandex_cloud_ml_sdk/_types/function.py @@ -7,17 +7,21 @@ if TYPE_CHECKING: from yandex_cloud_ml_sdk._sdk import BaseSDK + from yandex_cloud_ml_sdk._types.resource import BaseResource ModelTypeT = TypeVar('ModelTypeT', bound=BaseModel) -class BaseFunction(abc.ABC, Generic[ModelTypeT]): - _model_type: type[ModelTypeT] - - def __init__(self, name: str, sdk: BaseSDK): +class BaseFunction(abc.ABC): + def __init__(self, name: str, sdk: BaseSDK, parent_resource: BaseResource): self._name = name self._sdk = sdk + self._parent_resource = parent_resource + + +class BaseModelFunction(BaseFunction, Generic[ModelTypeT]): + _model_type: type[ModelTypeT] @abc.abstractmethod def __call__(self, *args, **kwargs) -> ModelTypeT: diff --git a/src/yandex_cloud_ml_sdk/_types/misc.py b/src/yandex_cloud_ml_sdk/_types/misc.py index ca7c4c8..e26d9c2 100644 --- a/src/yandex_cloud_ml_sdk/_types/misc.py +++ b/src/yandex_cloud_ml_sdk/_types/misc.py @@ -1,5 +1,7 @@ from __future__ import annotations +import os +import pathlib from typing import TypeVar, Union, cast from typing_extensions import TypeGuard @@ -28,3 +30,10 @@ def get_defined_value(obj: UndefinedOr[_T], default: _D) -> _T | _D: return cast(_T, obj) return cast(_D, default) + + +PathLike = Union[str, os.PathLike] + + +def coerce_path(path: PathLike) -> pathlib.Path: + return pathlib.Path(path) diff --git a/src/yandex_cloud_ml_sdk/_types/resource.py b/src/yandex_cloud_ml_sdk/_types/resource.py index 60f339a..afd04fa 100644 --- a/src/yandex_cloud_ml_sdk/_types/resource.py +++ b/src/yandex_cloud_ml_sdk/_types/resource.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: + from yandex_cloud_ml_sdk._client import AsyncCloudClient from yandex_cloud_ml_sdk._sdk import BaseSDK @@ -11,3 +12,11 @@ class BaseResource: def __init__(self, name: str, sdk: BaseSDK): self._name = name self._sdk = sdk + + @property + def _client(self) -> AsyncCloudClient: + return self._sdk._client + + @property + def _folder_id(self) -> str: + return self._sdk._folder_id diff --git a/src/yandex_cloud_ml_sdk/_utils/proto.py b/src/yandex_cloud_ml_sdk/_utils/proto.py new file mode 100644 index 0000000..b8a2882 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_utils/proto.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import Any + +from google.protobuf.json_format import MessageToDict +from google.protobuf.message import Message +from google.protobuf.timestamp_pb2 import Timestamp # pylint: disable=no-name-in-module + + +def proto_to_dict(message: Message) -> dict[str, Any]: + dct = MessageToDict( + message, + preserving_proto_field_name=True + ) + for descriptor in message.DESCRIPTOR.fields: + value = getattr(message, descriptor.name) + if isinstance(value, Timestamp): + dct[descriptor.name] = value.ToDatetime() + return dct diff --git a/tests/assistants/cassettes/test_files/test_file.gprc.json b/tests/assistants/cassettes/test_files/test_file.gprc.json new file mode 100644 index 0000000..94d213d --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file.gprc.json @@ -0,0 +1,558 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvt7ruv3ufdqbnaj7kri", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:43:46.721204Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:43:46.721204Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:43:46.721204Z" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvt7ruv3ufdqbnaj7kri?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T174346Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=74c8ee4e5497494337675b0f8ba18e9d4604bb141aca6b8f1b1db45b41e76361" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvt7ruv3ufdqbnaj7kri?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T174347Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=0feadbc181cee339853b4d119ca59c12a12e5823649f892b92b6bea40b65c29c" + } + } + }, + { + "request": { + "cls": "UpdateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri", + "updateMask": "name", + "name": "name" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvt7ruv3ufdqbnaj7kri", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:43:46.721204Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:43:47.102003Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:43:46.721204Z" + } + } + }, + { + "request": { + "cls": "UpdateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri", + "updateMask": "description", + "description": "description" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvt7ruv3ufdqbnaj7kri", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:43:46.721204Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:43:47.149817Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:43:46.721204Z" + } + } + }, + { + "request": { + "cls": "UpdateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri", + "updateMask": "labels", + "labels": { + "foo": "bar" + } + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvt7ruv3ufdqbnaj7kri", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:43:46.721204Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:43:47.182786Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:43:46.721204Z", + "labels": { + "foo": "bar" + } + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt7ruv3ufdqbnaj7kri" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_files/test_file.yaml b/tests/assistants/cassettes/test_files/test_file.yaml new file mode 100644 index 0000000..5d63d74 --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file.yaml @@ -0,0 +1,48 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvt7ruv3ufdqbnaj7kri?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T174346Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=74c8ee4e5497494337675b0f8ba18e9d4604bb141aca6b8f1b1db45b41e76361 + response: + body: + string: test file + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '9' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:17 GMT + Etag: + - '"f20d9f2072bbeb6691c0f9c5099b01f3"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:43:46 GMT + Server: + - nginx + X-Amz-Request-Id: + - 059cc4d4f5571074 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +version: 1 diff --git a/tests/assistants/cassettes/test_files/test_file_deleted.gprc.json b/tests/assistants/cassettes/test_files/test_file_deleted.gprc.json new file mode 100644 index 0000000..a32cbe9 --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file_deleted.gprc.json @@ -0,0 +1,429 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvthqdlg9nfrpsd54dgu", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:46:31.199169Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:46:31.199169Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:46:31.199169Z" + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvthqdlg9nfrpsd54dgu" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_files/test_file_get.gprc.json b/tests/assistants/cassettes/test_files/test_file_get.gprc.json new file mode 100644 index 0000000..b3b3170 --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file_get.gprc.json @@ -0,0 +1,456 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtrsu780k6h4bf5gt9a", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:48:18.317817Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:48:18.317817Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:48:18.317817Z" + } + } + }, + { + "request": { + "cls": "GetFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtrsu780k6h4bf5gt9a" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtrsu780k6h4bf5gt9a", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:48:18.317817Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:48:18.317817Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:48:18.317817Z" + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtrsu780k6h4bf5gt9a" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_files/test_file_list.gprc.json b/tests/assistants/cassettes/test_files/test_file_list.gprc.json new file mode 100644 index 0000000..5077a1c --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file_list.gprc.json @@ -0,0 +1,1873 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvt8ms6p5bu8dg6t1di0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "9", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.526595Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.526595Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.526595Z" + }, + { + "id": "fvtdvjji36bp0s7qq4dg", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "8", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.379068Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.379068Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.379068Z" + }, + { + "id": "fvttv61vpei2biu58r3u", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "7", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.220247Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.220247Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.220247Z" + }, + { + "id": "fvth5tn8vgplvpp46clc", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "6", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.083320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.083320Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.083320Z" + }, + { + "id": "fvt26dar7guq8hrut5hl", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "5", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.956220Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.956220Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.956220Z" + }, + { + "id": "fvt2vgfuv0eateakk1eu", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "4", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.828259Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.828259Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.828259Z" + }, + { + "id": "fvtp5659ibv75eiq04er", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "3", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.617449Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.617449Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.617449Z" + }, + { + "id": "fvtdpvrttmf4neeuooov", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "2", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.451784Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.451784Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.451784Z" + }, + { + "id": "fvtc939ughi46e0hgacb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "1", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.282885Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.282885Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.282885Z" + }, + { + "id": "fvtk0p9vvds0to8m2rbb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "0", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.083783Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.083783Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.083783Z" + }, + { + "id": "fvtpc8als2hkstovmvjb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:42:35.413383Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:42:35.875780Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:42:35.413383Z" + }, + { + "id": "fvtg5ggk07ij41tpj08m", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:35:35.385743Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:35:35.385743Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:35:35.385743Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzozNTozNS4zODU3NDNAZnZ0ZzVnZ2swN2lqNDF0cGowOG0=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageToken": "MjAyNC0wOS0yN1QxNzozNTozNS4zODU3NDNAZnZ0ZzVnZ2swN2lqNDF0cGowOG0=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "0", + "content": "dGVzdF9maWxlIDA=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtjgq2us8r579ceqnht", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "0", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.664832Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.664832Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.664832Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "1", + "content": "dGVzdF9maWxlIDE=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtocg9sh0mvhiqe0slf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "1", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.851406Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.851406Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.851406Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "2", + "content": "dGVzdF9maWxlIDI=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtdmq06qmdehrc1l6a1", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "2", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.980080Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.980080Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.980080Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "3", + "content": "dGVzdF9maWxlIDM=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtuacd8986o0bn832l1", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "3", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.166400Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.166400Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.166400Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "4", + "content": "dGVzdF9maWxlIDQ=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtji7n46r9rscb8n6t6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "4", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.325382Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.325382Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.325382Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "5", + "content": "dGVzdF9maWxlIDU=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtua4sjfh7lvo4ovu4k", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "5", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.466437Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.466437Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.466437Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "6", + "content": "dGVzdF9maWxlIDY=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtp9ka90o51vtict9pv", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "6", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.665747Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.665747Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.665747Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "7", + "content": "dGVzdF9maWxlIDc=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtqsgiciu69juh8goin", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "7", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.795925Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.795925Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.795925Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "8", + "content": "dGVzdF9maWxlIDg=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtn9b726gecupnhbncs", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "8", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.952443Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.952443Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.952443Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "9", + "content": "dGVzdF9maWxlIDk=" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtl7vl8ucbhs0vm9cqj", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "9", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:49.088021Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:49.088021Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:49.088021Z" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtl7vl8ucbhs0vm9cqj", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "9", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:49.088021Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:49.088021Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:49.088021Z" + }, + { + "id": "fvtn9b726gecupnhbncs", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "8", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.952443Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.952443Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.952443Z" + }, + { + "id": "fvtqsgiciu69juh8goin", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "7", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.795925Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.795925Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.795925Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1Njo0OC43OTU5MjVAZnZ0cXNnaWNpdTY5anVoOGdvaW4=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1Njo0OC43OTU5MjVAZnZ0cXNnaWNpdTY5anVoOGdvaW4=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtp9ka90o51vtict9pv", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "6", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.665747Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.665747Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.665747Z" + }, + { + "id": "fvtua4sjfh7lvo4ovu4k", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "5", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.466437Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.466437Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.466437Z" + }, + { + "id": "fvtji7n46r9rscb8n6t6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "4", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.325382Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.325382Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.325382Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1Njo0OC4zMjUzODJAZnZ0amk3bjQ2cjlyc2NiOG42dDY=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1Njo0OC4zMjUzODJAZnZ0amk3bjQ2cjlyc2NiOG42dDY=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtuacd8986o0bn832l1", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "3", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:48.166400Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:48.166400Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:48.166400Z" + }, + { + "id": "fvtdmq06qmdehrc1l6a1", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "2", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.980080Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.980080Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.980080Z" + }, + { + "id": "fvtocg9sh0mvhiqe0slf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "1", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.851406Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.851406Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.851406Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1Njo0Ny44NTE0MDZAZnZ0b2NnOXNoMG12aGlxZTBzbGY=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1Njo0Ny44NTE0MDZAZnZ0b2NnOXNoMG12aGlxZTBzbGY=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtjgq2us8r579ceqnht", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "0", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:47.664832Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:47.664832Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:47.664832Z" + }, + { + "id": "fvt8ms6p5bu8dg6t1di0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "9", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.526595Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.526595Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.526595Z" + }, + { + "id": "fvtdvjji36bp0s7qq4dg", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "8", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.379068Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.379068Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.379068Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNi4zNzkwNjhAZnZ0ZHZqamkzNmJwMHM3cXE0ZGc=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNi4zNzkwNjhAZnZ0ZHZqamkzNmJwMHM3cXE0ZGc=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvttv61vpei2biu58r3u", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "7", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.220247Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.220247Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.220247Z" + }, + { + "id": "fvth5tn8vgplvpp46clc", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "6", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:26.083320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:26.083320Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:26.083320Z" + }, + { + "id": "fvt26dar7guq8hrut5hl", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "5", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.956220Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.956220Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.956220Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNS45NTYyMjBAZnZ0MjZkYXI3Z3VxOGhydXQ1aGw=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNS45NTYyMjBAZnZ0MjZkYXI3Z3VxOGhydXQ1aGw=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvt2vgfuv0eateakk1eu", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "4", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.828259Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.828259Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.828259Z" + }, + { + "id": "fvtp5659ibv75eiq04er", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "3", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.617449Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.617449Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.617449Z" + }, + { + "id": "fvtdpvrttmf4neeuooov", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "2", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.451784Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.451784Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.451784Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNS40NTE3ODRAZnZ0ZHB2cnR0bWY0bmVldW9vb3Y=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo1NjoyNS40NTE3ODRAZnZ0ZHB2cnR0bWY0bmVldW9vb3Y=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtc939ughi46e0hgacb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "1", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.282885Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.282885Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.282885Z" + }, + { + "id": "fvtk0p9vvds0to8m2rbb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "0", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:56:25.083783Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:56:25.083783Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:56:25.083783Z" + }, + { + "id": "fvtpc8als2hkstovmvjb", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:42:35.413383Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:42:35.875780Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:42:35.413383Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzo0MjozNS40MTMzODNAZnZ0cGM4YWxzMmhrc3Rvdm12amI=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzo0MjozNS40MTMzODNAZnZ0cGM4YWxzMmhrc3Rvdm12amI=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "files": [ + { + "id": "fvtg5ggk07ij41tpj08m", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-09-27T17:35:35.385743Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-09-27T17:35:35.385743Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-04T17:35:35.385743Z" + } + ], + "nextPageToken": "MjAyNC0wOS0yN1QxNzozNTozNS4zODU3NDNAZnZ0ZzVnZ2swN2lqNDF0cGowOG0=" + } + } + }, + { + "request": { + "cls": "ListFilesRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageSize": "3", + "pageToken": "MjAyNC0wOS0yN1QxNzozNTozNS4zODU3NDNAZnZ0ZzVnZ2swN2lqNDF0cGowOG0=" + } + }, + "response": { + "cls": "ListFilesResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtl7vl8ucbhs0vm9cqj" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtl7vl8ucbhs0vm9cqj?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175649Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=45f0611590cf73aa3f2d302973aadd751f446b9afeab2f4738a71e4d4be422f9" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtn9b726gecupnhbncs" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtn9b726gecupnhbncs?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175649Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=95841ccdc9f332fa8476e0cef7a1d3c960655459d44ac6175dafc571185f0dfd" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtqsgiciu69juh8goin" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtqsgiciu69juh8goin?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=dc56e53407ce8a1998e395c2d2b3c1ab4fc534fdea9069879ed798593e9de860" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtp9ka90o51vtict9pv" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtp9ka90o51vtict9pv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=e7c48579899ac0f02646ca4a0c052ba20d0d978a61ed25904128abbd9309980d" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtua4sjfh7lvo4ovu4k" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtua4sjfh7lvo4ovu4k?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=ffd01070deb44299532f17d4caeb71143b9af41280866e5ced5ecafbe3a28bed" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtji7n46r9rscb8n6t6" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtji7n46r9rscb8n6t6?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=275ec98c054b4cf091c3bed5e36edcad8a8bcae9d3894d6a0e2af508cdc749e4" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtuacd8986o0bn832l1" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtuacd8986o0bn832l1?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=5f045736692ecd24673acb57cde8f3a60960125fc7ec5914cfb1c7bab7ae994a" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtdmq06qmdehrc1l6a1" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtdmq06qmdehrc1l6a1?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=8fbc62968e62594fd822cb6bec018e704370e4342d2af3e7f3b10788ed653cd3" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtocg9sh0mvhiqe0slf" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtocg9sh0mvhiqe0slf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=b8d40f32d9c41d0a9a2ef2fcb5c88161ead53965085a22c4950699a5a469b549" + } + } + }, + { + "request": { + "cls": "GetFileUrlRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtjgq2us8r579ceqnht" + } + }, + "response": { + "cls": "GetFileUrlResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "url": "https://assistant-files.storage.yandexcloud.net/fvtjgq2us8r579ceqnht?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=9506023013a7f418420fa2aa2e93f278a6df2438e64434d6288b5d887bc4ee26" + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtl7vl8ucbhs0vm9cqj" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtn9b726gecupnhbncs" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtqsgiciu69juh8goin" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtp9ka90o51vtict9pv" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtua4sjfh7lvo4ovu4k" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtji7n46r9rscb8n6t6" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtuacd8986o0bn832l1" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtdmq06qmdehrc1l6a1" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtocg9sh0mvhiqe0slf" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtjgq2us8r579ceqnht" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt8ms6p5bu8dg6t1di0" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtdvjji36bp0s7qq4dg" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvttv61vpei2biu58r3u" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvth5tn8vgplvpp46clc" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt26dar7guq8hrut5hl" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt2vgfuv0eateakk1eu" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtp5659ibv75eiq04er" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtdpvrttmf4neeuooov" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtc939ughi46e0hgacb" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtk0p9vvds0to8m2rbb" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtpc8als2hkstovmvjb" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtg5ggk07ij41tpj08m" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_files/test_file_list.yaml b/tests/assistants/cassettes/test_files/test_file_list.yaml new file mode 100644 index 0000000..0ceeeb7 --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file_list.yaml @@ -0,0 +1,462 @@ +interactions: +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtl7vl8ucbhs0vm9cqj?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175649Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=45f0611590cf73aa3f2d302973aadd751f446b9afeab2f4738a71e4d4be422f9 + response: + body: + string: test_file 9 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:17 GMT + Etag: + - '"34a5e2a583d047eb73d094a37c57761d"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:49 GMT + Server: + - nginx + X-Amz-Request-Id: + - 5f4f56c89d0eaa50 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtn9b726gecupnhbncs?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175649Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=95841ccdc9f332fa8476e0cef7a1d3c960655459d44ac6175dafc571185f0dfd + response: + body: + string: test_file 8 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:17 GMT + Etag: + - '"cdaa711f6610bf585997ac76271f60e8"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:49 GMT + Server: + - nginx + X-Amz-Request-Id: + - c933125b62481bfd + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtqsgiciu69juh8goin?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=dc56e53407ce8a1998e395c2d2b3c1ab4fc534fdea9069879ed798593e9de860 + response: + body: + string: test_file 7 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:17 GMT + Etag: + - '"ac93527c5b94d0d6651d16b64c24cc5e"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - e2c18a9a7ba4d418 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtp9ka90o51vtict9pv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=e7c48579899ac0f02646ca4a0c052ba20d0d978a61ed25904128abbd9309980d + response: + body: + string: test_file 6 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:17 GMT + Etag: + - '"911df1ef9342387515c9596d468c0fff"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - 6ba6dd13ca7fa6d3 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtua4sjfh7lvo4ovu4k?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=ffd01070deb44299532f17d4caeb71143b9af41280866e5ced5ecafbe3a28bed + response: + body: + string: test_file 5 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"9c229ae801ee4f332394fc3c8c6539b9"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - b766f6528d3821a7 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtji7n46r9rscb8n6t6?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=275ec98c054b4cf091c3bed5e36edcad8a8bcae9d3894d6a0e2af508cdc749e4 + response: + body: + string: test_file 4 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"55f952df45bf503b97185bbca393609e"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - 8a2820aa058cbdfc + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtuacd8986o0bn832l1?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=5f045736692ecd24673acb57cde8f3a60960125fc7ec5914cfb1c7bab7ae994a + response: + body: + string: test_file 3 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"f634d70f4d0ee0e1879729253b906cc5"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - 11e75d2b2016fcee + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtdmq06qmdehrc1l6a1?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=8fbc62968e62594fd822cb6bec018e704370e4342d2af3e7f3b10788ed653cd3 + response: + body: + string: test_file 2 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"622514a1542dfee61176c9c2ed6b1300"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:48 GMT + Server: + - nginx + X-Amz-Request-Id: + - b11544e3842d9d2f + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtocg9sh0mvhiqe0slf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=b8d40f32d9c41d0a9a2ef2fcb5c88161ead53965085a22c4950699a5a469b549 + response: + body: + string: test_file 1 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"69e7d012ab4e422fef541a48370398b4"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:47 GMT + Server: + - nginx + X-Amz-Request-Id: + - 8a082300c2ce4638 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +- request: + body: '' + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + host: + - assistant-files.storage.yandexcloud.net + user-agent: + - python-httpx/0.27.0 + method: GET + uri: https://assistant-files.storage.yandexcloud.net/fvtjgq2us8r579ceqnht?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20240927T175650Z&X-Amz-SignedHeaders=host&X-Amz-Credential=YCAJEHiVgmYku8GTZkpBffKkV%2F20240927%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=9506023013a7f418420fa2aa2e93f278a6df2438e64434d6288b5d887bc4ee26 + response: + body: + string: test_file 0 + headers: + Accept-Ranges: + - bytes + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - text/plain + Date: + - Fri, 27 Sep 2024 18:25:18 GMT + Etag: + - '"900d251541164d17761945cef7feca43"' + Keep-Alive: + - timeout=60 + Last-Modified: + - Fri, 27 Sep 2024 17:56:47 GMT + Server: + - nginx + X-Amz-Request-Id: + - 215e25a3212d3a12 + X-Amz-Server-Side-Encryption: + - aws:kms + X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id: + - abj06h6rner491sgu7hg + status: + code: 200 + message: OK +version: 1 diff --git a/tests/assistants/test_files.py b/tests/assistants/test_files.py new file mode 100644 index 0000000..82375c7 --- /dev/null +++ b/tests/assistants/test_files.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.fixture(name='test_file_path') +def fixture_test_file_path(tmp_path): + path = tmp_path / 'test_file' + path.write_bytes(b'test file') + yield path + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_file(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + + content = await file.download_as_bytes() + assert content == b'test file' + + url = await file.get_url() + assert url.startswith('https://') + + for field, value in ( + ('name', 'name'), + ('description', 'description'), + ('labels', {'foo': 'bar'}), + ): + assert getattr(file, field) is None + + new_file = await file.update( + **{field: value} + ) + + assert new_file is file + + assert getattr(file, field) == value + + await file.delete() + + +@pytest.mark.allow_grpc +async def test_file_deleted(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + await file.delete() + + for method in ('delete', 'get_url', 'download_as_bytes', 'update'): + with pytest.raises(ValueError): + await getattr(file, method)() + + +@pytest.mark.allow_grpc +async def test_file_get(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + + second_file = await async_sdk.files.get(file.id) + + assert file.id == second_file.id + + # I hope is temporary + assert file is not second_file + + await file.delete() + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_file_list(async_sdk, tmp_path): + paths = [] + for i in range(10): + path = tmp_path / str(i) + path.write_text(f'test_file {i}', encoding='utf-8') + paths.append(path) + + present_files = set() + files = [f async for f in async_sdk.files.list()] + for file in files: + present_files.add(file.id) + + for i, path in enumerate(paths): + await async_sdk.files.upload(path, name=str(i)) + + files = [f async for f in async_sdk.files.list(page_size=3)] + + for file in files: + if file.id in present_files: + continue + + content = await file.download_as_bytes() + content = content.decode('utf-8') + assert content == f'test_file {file.name}' + + for file in files: + await file.delete() diff --git a/tests/conftest.py b/tests/conftest.py index 4a5fff4..bb1a941 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -136,7 +136,15 @@ def fixture_async_sdk( retry_policy: RetryPolicy, test_client: MockClient | None, ) -> AsyncYCloudML: - sdk = AsyncYCloudML(folder_id=folder_id, interceptors=interceptors, auth=auth, retry_policy=retry_policy) + sdk = AsyncYCloudML( + folder_id=folder_id, + interceptors=interceptors, + auth=auth, + retry_policy=retry_policy, + service_map={ + 'ai-files': 'assistant.api.cloud.yandex.net' + } + ) if test_client: sdk._client = test_client return sdk diff --git a/tox.ini b/tox.ini index 318482b..d59cde8 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,6 @@ deps = commands = pytest \ - --mypy \ --flakes \ --pylint \ --doctest-modules \ @@ -20,7 +19,7 @@ commands = deps = -r test_requirements.txt numpy - langchain-core + langchain-core<=0.2.41 commands = pytest \ From 67f509d45b279648a7a0edeefde7fad89e638bcd Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Tue, 8 Oct 2024 18:38:55 +0200 Subject: [PATCH 02/13] Rename old resource to domain & add resource class (#3) --- .../_files/{resource.py => domain.py} | 16 ++-- src/yandex_cloud_ml_sdk/_files/file.py | 85 ++----------------- src/yandex_cloud_ml_sdk/_models/__init__.py | 4 +- src/yandex_cloud_ml_sdk/_sdk.py | 10 +-- src/yandex_cloud_ml_sdk/_types/domain.py | 22 +++++ src/yandex_cloud_ml_sdk/_types/function.py | 4 +- src/yandex_cloud_ml_sdk/_types/resource.py | 85 +++++++++++++++++-- 7 files changed, 124 insertions(+), 102 deletions(-) rename src/yandex_cloud_ml_sdk/_files/{resource.py => domain.py} (90%) create mode 100644 src/yandex_cloud_ml_sdk/_types/domain.py diff --git a/src/yandex_cloud_ml_sdk/_files/resource.py b/src/yandex_cloud_ml_sdk/_files/domain.py similarity index 90% rename from src/yandex_cloud_ml_sdk/_files/resource.py rename to src/yandex_cloud_ml_sdk/_files/domain.py index 945273a..272f9bd 100644 --- a/src/yandex_cloud_ml_sdk/_files/resource.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import Generic, TypeVar +from typing import AsyncIterator, Generic, TypeVar from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile from yandex.cloud.ai.files.v1.file_service_pb2 import ( @@ -9,8 +9,8 @@ ) from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub +from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.misc import UNDEFINED, PathLike, UndefinedOr, coerce_path, get_defined_value -from yandex_cloud_ml_sdk._types.resource import BaseResource from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .file import AsyncFile, BaseFile, File @@ -18,7 +18,7 @@ FileTypeT = TypeVar('FileTypeT', bound=BaseFile) -class BaseFiles(BaseResource, Generic[FileTypeT]): +class BaseFiles(BaseDomain, Generic[FileTypeT]): _file_impl: type[FileTypeT] async def _upload_bytes( @@ -48,7 +48,7 @@ async def _upload_bytes( expected_type=ProtoFile, ) - return self._file_impl.from_proto(proto=response, sdk=self._sdk) + return self._file_impl._from_proto(proto=response, sdk=self._sdk) async def _upload( self, @@ -75,7 +75,7 @@ async def _get( file_id: str, *, timeout: float = 60, - ): + ) -> FileTypeT: # TODO: we need a global per-sdk cache on file_ids to rule out # possibility we have two Files with same ids but different fields request = GetFileRequest(file_id=file_id) @@ -88,7 +88,7 @@ async def _get( expected_type=ProtoFile, ) - return self._file_impl.from_proto(proto=response, sdk=self._sdk) + return self._file_impl._from_proto(proto=response, sdk=self._sdk) async def _list( self, @@ -96,7 +96,7 @@ async def _list( page_size: UndefinedOr[int] = UNDEFINED, page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 - ): + ) -> AsyncIterator[FileTypeT]: page_token_ = get_defined_value(page_token, '') page_size_ = get_defined_value(page_size, 0) @@ -115,7 +115,7 @@ async def _list( expected_type=ListFilesResponse, ) for file_proto in response.files: - yield self._file_impl.from_proto(proto=file_proto, sdk=self._sdk) + yield self._file_impl._from_proto(proto=file_proto, sdk=self._sdk) if not response.files: return diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py index 434a2d6..a8d434a 100644 --- a/src/yandex_cloud_ml_sdk/_files/file.py +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -2,13 +2,10 @@ from __future__ import annotations import dataclasses -import functools -from asyncio import Lock from datetime import datetime -from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar import httpx -from typing_extensions import Concatenate, ParamSpec, Self +from typing_extensions import Self from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile from yandex.cloud.ai.files.v1.file_service_pb2 import ( DeleteFileRequest, DeleteFileResponse, GetFileUrlRequest, GetFileUrlResponse, UpdateFileRequest @@ -16,48 +13,13 @@ from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value -from yandex_cloud_ml_sdk._utils.proto import proto_to_dict +from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync -if TYPE_CHECKING: - from yandex_cloud_ml_sdk._client import AsyncCloudClient - from yandex_cloud_ml_sdk._sdk import BaseSDK - - -P = ParamSpec('P') -T = TypeVar('T') - - -def safe(method: Callable[Concatenate[BaseFile, P], Awaitable[T]]) -> Callable[Concatenate[BaseFile, P], Awaitable[T]]: - @functools.wraps(method) - async def inner(self: BaseFile, *args: P.args, **kwargs: P.kwargs) -> T: - async with self._lock: # pylint: disable=protected-access - action = method.__name__.lstrip('_') - if self._deleted: # pylint: disable=protected-access - raise ValueError(f"you can't perform an action '{action}' on file '{self.id}' because it is deleted") - - return await method(self, *args, **kwargs) - - return inner - @dataclasses.dataclass(frozen=True) -class BaseFile: - _sdk: BaseSDK = dataclasses.field(repr=False) - _lock: Lock = dataclasses.field(repr=False) - _deleted: bool = dataclasses.field(repr=False) - - id: str - - @property - def _client(self) -> AsyncCloudClient: - return self._sdk._client - - def _assert_not_deleted(self, action: str) -> None: - if self._deleted: - raise ValueError(f"you can't perform action '{action}' on this file because it is deleted") - - @safe +class BaseFile(BaseDeleteableResource): + @safe_on_delete async def _get_url( self, *, @@ -75,7 +37,7 @@ async def _get_url( return response.url - @safe + @safe_on_delete async def _update( self, *, @@ -114,7 +76,7 @@ async def _update( return self - @safe + @safe_on_delete async def _delete( self, *, @@ -131,14 +93,14 @@ async def _delete( ) object.__setattr__(self, '_deleted', True) - @safe + @safe_on_delete async def _download_as_bytes( self, *, chunk_size: int = 32768, timeout: float = 60 ) -> bytes: - # I didn't invent better way to use this function without a @safe-lock + # I didn't invent better way to use this function without a @safe_on_delete-lock url = await self._get_url.__wrapped__(self, timeout=timeout) # type: ignore[attr-defined] async with httpx.AsyncClient() as client: @@ -151,37 +113,6 @@ async def _download_as_bytes( return file_bytes - @classmethod - def _kwargs_from_message(cls, proto: ProtoFile) -> dict[str, Any]: - fields = dataclasses.fields(cls) - data = proto_to_dict(proto) - kwargs = {} - for field in fields: - name = field.name - if name.startswith('_'): - continue - - kwargs[name] = data.get(name) - - return kwargs - - @classmethod - def from_proto(cls, *, sdk: BaseSDK, proto: ProtoFile) -> Self: - return cls( - _sdk=sdk, - _lock=Lock(), - _deleted=False, - **cls._kwargs_from_message(proto), - ) - - def _update_from_proto(self, proto: ProtoFile) -> Self: - # We want to File to be a immutable, but also we need - # to maintain a inner status after updating and such - kwargs = self._kwargs_from_message(proto) - for key, value in kwargs.items(): - object.__setattr__(self, key, value) - return self - @dataclasses.dataclass(frozen=True) class RichFile(BaseFile): diff --git a/src/yandex_cloud_ml_sdk/_models/__init__.py b/src/yandex_cloud_ml_sdk/_models/__init__.py index ce8c30c..00d85c4 100644 --- a/src/yandex_cloud_ml_sdk/_models/__init__.py +++ b/src/yandex_cloud_ml_sdk/_models/__init__.py @@ -4,8 +4,8 @@ from get_annotations import get_annotations +from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.function import BaseFunction -from yandex_cloud_ml_sdk._types.resource import BaseResource from .completions.function import AsyncCompletions, Completions from .text_classifiers.function import AsyncTextClassifiers, TextClassifiers @@ -15,7 +15,7 @@ from yandex_cloud_ml_sdk._sdk import BaseSDK -class BaseModels(BaseResource): +class BaseModels(BaseDomain): def __init__(self, name: str, sdk: BaseSDK): super().__init__(name=name, sdk=sdk) self._init_functions() diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 441dba4..332dde2 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -11,11 +11,11 @@ from ._auth import BaseAuth from ._client import AsyncCloudClient -from ._files.resource import AsyncFiles, Files +from ._files.domain import AsyncFiles, Files from ._models import AsyncModels, Models from ._retry import RetryPolicy +from ._types.domain import BaseDomain from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined -from ._types.resource import BaseResource class BaseSDK: @@ -61,12 +61,12 @@ def __init__( ) self._folder_id = folder_id - self._init_resources() + self._init_domains() - def _init_resources(self) -> None: + def _init_domains(self) -> None: members: dict[str, type] = get_annotations(self.__class__, eval_str=True) for member_name, member in members.items(): - if inspect.isclass(member) and issubclass(member, BaseResource): + if inspect.isclass(member) and issubclass(member, BaseDomain): resource = member(name=member_name, sdk=self) setattr(self, member_name, resource) diff --git a/src/yandex_cloud_ml_sdk/_types/domain.py b/src/yandex_cloud_ml_sdk/_types/domain.py new file mode 100644 index 0000000..5ac44a9 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_types/domain.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._client import AsyncCloudClient + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +class BaseDomain: + # TODO: add some repr, description and such + def __init__(self, name: str, sdk: BaseSDK): + self._name = name + self._sdk = sdk + + @property + def _client(self) -> AsyncCloudClient: + return self._sdk._client + + @property + def _folder_id(self) -> str: + return self._sdk._folder_id diff --git a/src/yandex_cloud_ml_sdk/_types/function.py b/src/yandex_cloud_ml_sdk/_types/function.py index c52f41b..843c7c3 100644 --- a/src/yandex_cloud_ml_sdk/_types/function.py +++ b/src/yandex_cloud_ml_sdk/_types/function.py @@ -7,14 +7,14 @@ if TYPE_CHECKING: from yandex_cloud_ml_sdk._sdk import BaseSDK - from yandex_cloud_ml_sdk._types.resource import BaseResource + from yandex_cloud_ml_sdk._types.domain import BaseDomain ModelTypeT = TypeVar('ModelTypeT', bound=BaseModel) class BaseFunction(abc.ABC): - def __init__(self, name: str, sdk: BaseSDK, parent_resource: BaseResource): + def __init__(self, name: str, sdk: BaseSDK, parent_resource: BaseDomain): self._name = name self._sdk = sdk self._parent_resource = parent_resource diff --git a/src/yandex_cloud_ml_sdk/_types/resource.py b/src/yandex_cloud_ml_sdk/_types/resource.py index afd04fa..ef293d0 100644 --- a/src/yandex_cloud_ml_sdk/_types/resource.py +++ b/src/yandex_cloud_ml_sdk/_types/resource.py @@ -1,22 +1,91 @@ from __future__ import annotations -from typing import TYPE_CHECKING +import asyncio +import dataclasses +import functools +from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar + +from google.protobuf.message import Message +from typing_extensions import Concatenate, ParamSpec, Self + +from yandex_cloud_ml_sdk._utils.proto import proto_to_dict if TYPE_CHECKING: from yandex_cloud_ml_sdk._client import AsyncCloudClient from yandex_cloud_ml_sdk._sdk import BaseSDK +@dataclasses.dataclass(frozen=True) class BaseResource: - # TODO: add some repr, description and such - def __init__(self, name: str, sdk: BaseSDK): - self._name = name - self._sdk = sdk + id: str + + _sdk: BaseSDK = dataclasses.field(repr=False) @property def _client(self) -> AsyncCloudClient: return self._sdk._client - @property - def _folder_id(self) -> str: - return self._sdk._folder_id + @classmethod + def _kwargs_from_message(cls, proto: Message) -> dict[str, Any]: + fields = dataclasses.fields(cls) + data = proto_to_dict(proto) + kwargs = {} + for field in fields: + name = field.name + if name.startswith('_'): + continue + + kwargs[name] = data.get(name) + + return kwargs + + @classmethod + def _from_proto(cls, *, sdk: BaseSDK, proto: Message) -> Self: + return cls( + _sdk=sdk, + **cls._kwargs_from_message(proto), + ) + + def _update_from_proto(self, proto: Message) -> Self: + # We want to Resource to be a immutable, but also we need + # to maintain a inner status after updating and such + kwargs = self._kwargs_from_message(proto) + for key, value in kwargs.items(): + object.__setattr__(self, key, value) + return self + + +@dataclasses.dataclass(frozen=True) +class BaseDeleteableResource(BaseResource): + _lock: asyncio.Lock = dataclasses.field(repr=False) + _deleted: bool = dataclasses.field(repr=False) + + @classmethod + def _from_proto(cls, *, sdk: BaseSDK, proto: Message) -> Self: + return cls( + _sdk=sdk, + _lock=asyncio.Lock(), + _deleted=False, + **cls._kwargs_from_message(proto), + ) + + +P = ParamSpec('P') +T = TypeVar('T') +R = TypeVar('R', bound=BaseDeleteableResource) + + +def safe_on_delete( + method: Callable[Concatenate[R, P], Awaitable[T]] +) -> Callable[Concatenate[R, P], Awaitable[T]]: + @functools.wraps(method) + async def inner(self: R, *args: P.args, **kwargs: P.kwargs) -> T: + async with self._lock: # pylint: disable=protected-access + action = method.__name__.lstrip('_') + if self._deleted: # pylint: disable=protected-access + klass = self.__class__.__name__ + raise ValueError(f"you can't perform an action '{action}' on {klass}='{self.id}' because it is deleted") + + return await method(self, *args, **kwargs) + + return inner From ccd5b5d6e92e7211e06f385265a7ae28af41dad3 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Thu, 10 Oct 2024 16:27:00 +0200 Subject: [PATCH 03/13] Introduce threads service (#4) --- examples/async/assistants/threads.py | 32 + src/yandex_cloud_ml_sdk/_files/domain.py | 2 +- src/yandex_cloud_ml_sdk/_messages/__init__.py | 0 src/yandex_cloud_ml_sdk/_messages/domain.py | 100 ++ src/yandex_cloud_ml_sdk/_messages/message.py | 54 + src/yandex_cloud_ml_sdk/_sdk.py | 8 + src/yandex_cloud_ml_sdk/_threads/__init__.py | 0 src/yandex_cloud_ml_sdk/_threads/domain.py | 115 ++ src/yandex_cloud_ml_sdk/_threads/thread.py | 139 +++ .../test_messages/test_message.gprc.json | 475 ++++++++ .../test_messages/test_message_get.gprc.json | 502 ++++++++ .../test_messages/test_message_list.gprc.json | 1079 +++++++++++++++++ .../test_threads/test_thread.gprc.json | 522 ++++++++ .../test_thread_deleted.gprc.json | 428 +++++++ .../test_threads/test_thread_get.gprc.json | 455 +++++++ .../test_threads/test_thread_list.gprc.json | 1000 +++++++++++++++ .../test_thread_read_write.gprc.json | 1079 +++++++++++++++++ tests/assistants/test_messages.py | 60 + tests/assistants/test_threads.py | 85 ++ tests/conftest.py | 3 +- 20 files changed, 6136 insertions(+), 2 deletions(-) create mode 100755 examples/async/assistants/threads.py create mode 100644 src/yandex_cloud_ml_sdk/_messages/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_messages/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_messages/message.py create mode 100644 src/yandex_cloud_ml_sdk/_threads/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_threads/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_threads/thread.py create mode 100644 tests/assistants/cassettes/test_messages/test_message.gprc.json create mode 100644 tests/assistants/cassettes/test_messages/test_message_get.gprc.json create mode 100644 tests/assistants/cassettes/test_messages/test_message_list.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread_deleted.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread_get.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread_list.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread_read_write.gprc.json create mode 100644 tests/assistants/test_messages.py create mode 100644 tests/assistants/test_threads.py diff --git a/examples/async/assistants/threads.py b/examples/async/assistants/threads.py new file mode 100755 index 0000000..390bfe8 --- /dev/null +++ b/examples/async/assistants/threads.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio + +from yandex_cloud_ml_sdk import AsyncYCloudML + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + thread = await sdk.threads.create(name='foo') + second = await sdk.threads.get(thread.id) + + await thread.write("content") + await second.write("content2") + async for message in thread: + print(message) + print(message.text) + + async for thread in sdk.threads.list(): + await thread.delete() + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/src/yandex_cloud_ml_sdk/_files/domain.py b/src/yandex_cloud_ml_sdk/_files/domain.py index 272f9bd..38dfdfa 100644 --- a/src/yandex_cloud_ml_sdk/_files/domain.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -120,7 +120,7 @@ async def _list( if not response.files: return - page_token = response.next_page_token + page_token_ = response.next_page_token class AsyncFiles(BaseFiles[AsyncFile]): diff --git a/src/yandex_cloud_ml_sdk/_messages/__init__.py b/src/yandex_cloud_ml_sdk/_messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_messages/domain.py b/src/yandex_cloud_ml_sdk/_messages/domain.py new file mode 100644 index 0000000..776ab4e --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_messages/domain.py @@ -0,0 +1,100 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import AsyncIterator + +from yandex.cloud.ai.assistants.v1.threads.message_pb2 import ContentPart +from yandex.cloud.ai.assistants.v1.threads.message_pb2 import Message as ProtoMessage +from yandex.cloud.ai.assistants.v1.threads.message_pb2 import MessageContent, Text +from yandex.cloud.ai.assistants.v1.threads.message_service_pb2 import ( + CreateMessageRequest, GetMessageRequest, ListMessagesRequest +) +from yandex.cloud.ai.assistants.v1.threads.message_service_pb2_grpc import MessageServiceStub + +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .message import Message + + +class BaseMessages(BaseDomain): + _message_impl = Message + + async def _create( + self, + content: str, + *, + thread_id: str, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + request = CreateMessageRequest( + thread_id=thread_id, + content=MessageContent( + content=[ContentPart( + text=Text(content=content) + )] + ), + labels=get_defined_value(labels, {}), + ) + + async with self._client.get_service_stub(MessageServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoMessage, + ) + + return self._message_impl._from_proto(proto=response, sdk=self._sdk) + + async def _get( + self, + *, + thread_id: str, + message_id: str, + timeout: float = 60, + ) -> Message: + # TODO: we need a global per-sdk cache on ids to rule out + # possibility we have two Messages with same ids but different fields + request = GetMessageRequest(thread_id=thread_id, message_id=message_id) + + async with self._client.get_service_stub(MessageServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoMessage, + ) + + return self._message_impl._from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + thread_id: str, + timeout: float = 60 + ) -> AsyncIterator[Message]: + request = ListMessagesRequest(thread_id=thread_id) + + async with self._client.get_service_stub(MessageServiceStub, timeout=timeout) as stub: + async for response in self._client.call_service_stream( + stub.List, + request, + timeout=timeout, + expected_type=ProtoMessage, + ): + yield self._message_impl._from_proto(proto=response, sdk=self._sdk) + + +class AsyncMessages(BaseMessages): + get = BaseMessages._get + create = BaseMessages._create + list = BaseMessages._list + + +class Messages(BaseMessages): + get = run_sync(BaseMessages._get) + create = run_sync(BaseMessages._create) + list = run_sync_generator(BaseMessages._list) diff --git a/src/yandex_cloud_ml_sdk/_messages/message.py b/src/yandex_cloud_ml_sdk/_messages/message.py new file mode 100644 index 0000000..29f440b --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_messages/message.py @@ -0,0 +1,54 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +from datetime import datetime +from typing import Any + +from yandex.cloud.ai.assistants.v1.threads.message_pb2 import Message as ProtoMessage + +from yandex_cloud_ml_sdk._types.resource import BaseResource + + +@dataclasses.dataclass(frozen=True) +class Author: + id: str + role: str + + +@dataclasses.dataclass(frozen=True) +class Message(BaseResource): + thread_id: str + created_by: str + created_at: datetime + labels: dict[str, str] | None + parts: list[Any] + author: Author + + @classmethod + def _kwargs_from_message(cls, proto: ProtoMessage) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto) + parts: list[Any] = [] + + for part in proto.content.content: + if hasattr(part, 'text'): + parts.append(part.text.content) + else: + raise NotImplementedError( + 'messages with non-string content are not supported in this SDK version' + ) + + kwargs['parts'] = parts + kwargs['author'] = Author( + role=proto.author.role, + id=proto.author.id + ) + + return kwargs + + @property + def text(self): + return '\n'.join( + part for part in self.parts + if isinstance(part, str) + ) diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 332dde2..5def565 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -12,13 +12,17 @@ from ._auth import BaseAuth from ._client import AsyncCloudClient from ._files.domain import AsyncFiles, Files +from ._messages.domain import AsyncMessages, BaseMessages, Messages from ._models import AsyncModels, Models from ._retry import RetryPolicy +from ._threads.domain import AsyncThreads, Threads from ._types.domain import BaseDomain from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined class BaseSDK: + _messages: BaseMessages + def __init__( self, *, @@ -129,8 +133,12 @@ def _get_event_loop() -> asyncio.AbstractEventLoop: class AsyncYCloudML(BaseSDK): models: AsyncModels files: AsyncFiles + threads: AsyncThreads + _messages: AsyncMessages class YCloudML(BaseSDK): models: Models files: Files + threads: Threads + _messages: Messages diff --git a/src/yandex_cloud_ml_sdk/_threads/__init__.py b/src/yandex_cloud_ml_sdk/_threads/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_threads/domain.py b/src/yandex_cloud_ml_sdk/_threads/domain.py new file mode 100644 index 0000000..a968868 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_threads/domain.py @@ -0,0 +1,115 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import AsyncIterator, Generic, TypeVar + +from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread +from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2 import ( + CreateThreadRequest, GetThreadRequest, ListThreadsRequest, ListThreadsResponse +) +from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2_grpc import ThreadServiceStub + +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .thread import AsyncThread, BaseThread, Thread + +ThreadTypeT = TypeVar('ThreadTypeT', bound=BaseThread) + + +class BaseThreads(BaseDomain, Generic[ThreadTypeT]): + _thread_impl: type[ThreadTypeT] + + async def _create( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> ThreadTypeT: + request = CreateThreadRequest( + folder_id=self._folder_id, + name=get_defined_value(name, ''), + description=get_defined_value(description, ''), + labels=get_defined_value(labels, {}), + ) + + async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoThread, + ) + + return self._thread_impl._from_proto(proto=response, sdk=self._sdk) + + async def _get( + self, + thread_id: str, + *, + timeout: float = 60, + ) -> ThreadTypeT: + # TODO: we need a global per-sdk cache on ids to rule out + # possibility we have two Threads with same ids but different fields + request = GetThreadRequest(thread_id=thread_id) + + async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoThread, + ) + + return self._thread_impl._from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[ThreadTypeT]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: + while True: + request = ListThreadsRequest( + folder_id=self._folder_id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListThreadsResponse, + ) + for thread_proto in response.threads: + yield self._thread_impl._from_proto(proto=thread_proto, sdk=self._sdk) + + if not response.threads: + return + + page_token_ = response.next_page_token + + +class AsyncThreads(BaseThreads[AsyncThread]): + _thread_impl = AsyncThread + + get = BaseThreads._get + create = BaseThreads._create + list = BaseThreads._list + + +class Threads(BaseThreads[Thread]): + _thread_impl = Thread + + get = run_sync(BaseThreads._get) + create = run_sync(BaseThreads._create) + list = run_sync_generator(BaseThreads._list) diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py new file mode 100644 index 0000000..2f027cb --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -0,0 +1,139 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +from datetime import datetime +from typing import AsyncIterator + +from typing_extensions import Self +from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread +from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2 import ( + DeleteThreadRequest, DeleteThreadResponse, UpdateThreadRequest +) +from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2_grpc import ThreadServiceStub + +from yandex_cloud_ml_sdk._messages.message import Message +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + + +@dataclasses.dataclass(frozen=True) +class BaseThread(BaseDeleteableResource): + @safe_on_delete + async def _update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Self: + name_ = get_defined_value(name, '') + description_ = get_defined_value(description, '') + labels_ = get_defined_value(labels, {}) + + request = UpdateThreadRequest( + thread_id=self.id, + name=name_, + description=description_, + labels=labels_, + ) + + for key, value in ( + ('name', name_), + ('description', description_), + ('labels', labels_) + ): + if value is not None: + request.update_mask.paths.append(key) + + async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Update, + request, + timeout=timeout, + expected_type=ProtoThread, + ) + self._update_from_proto(response) + + return self + + @safe_on_delete + async def _delete( + self, + *, + timeout: float = 60, + ) -> None: + request = DeleteThreadRequest(thread_id=self.id) + + async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: + await self._client.call_service( + stub.Delete, + request, + timeout=timeout, + expected_type=DeleteThreadResponse, + ) + object.__setattr__(self, '_deleted', True) + + @safe_on_delete + async def _write( + self, + content: str, + *, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + # pylint: disable-next=protected-access + return await self._sdk._messages._create( + thread_id=self.id, + content=content, + labels=labels, + timeout=timeout + ) + + async def _read( + self, + *, + timeout: float = 60, + ) -> AsyncIterator[Message]: + # NB: in other methods it is solved via @safe decorator, but it is doesn't work + # with iterators, so, temporary here will be small copypaste + # Also I'm not sure enough if we need to put whole thread reading under a lock + if self._deleted: + action = 'read' + klass = self.__class__.__name__ + raise ValueError(f"you can't perform an action '{action}' on {klass}='{self.id}' because it is deleted") + + # pylint: disable-next=protected-access + async for message in self._sdk._messages._list(thread_id=self.id, timeout=timeout): + yield message + + +@dataclasses.dataclass(frozen=True) +class RichThread(BaseThread): + name: str | None + description: str | None + mime_type: str + created_by: str + created_at: datetime + updated_by: str + updated_at: datetime + expires_at: datetime + labels: dict[str, str] | None + + +class AsyncThread(RichThread): + update = RichThread._update + delete = RichThread._delete + write = RichThread._write + read = RichThread._read + __aiter__ = RichThread._read + + +class Thread(RichThread): + update = run_sync(RichThread._update) + delete = run_sync(RichThread._delete) + write = run_sync(RichThread._write) + read = run_sync_generator(RichThread._read) + __iter__ = run_sync_generator(RichThread._read) diff --git a/tests/assistants/cassettes/test_messages/test_message.gprc.json b/tests/assistants/cassettes/test_messages/test_message.gprc.json new file mode 100644 index 0000000..f2d6eb2 --- /dev/null +++ b/tests/assistants/cassettes/test_messages/test_message.gprc.json @@ -0,0 +1,475 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtdau7nugneg7src7jq", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt83tco9sr23t13qvo2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:16.153971Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:21:16.153971Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:21:16.153971Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvtdau7nugneg7src7jq", + "labels": { + "foo": "bar" + }, + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtllnag6l7fbe09vgii", + "threadId": "fvtdau7nugneg7src7jq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:16.363275Z", + "author": { + "id": "fvt83tco9sr23t13qvo2", + "role": "USER" + }, + "labels": { + "foo": "bar" + }, + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtdau7nugneg7src7jq" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_messages/test_message_get.gprc.json b/tests/assistants/cassettes/test_messages/test_message_get.gprc.json new file mode 100644 index 0000000..622c8e1 --- /dev/null +++ b/tests/assistants/cassettes/test_messages/test_message_get.gprc.json @@ -0,0 +1,502 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtf7ekfbe6sif1ftnab", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt1hbn6kjb6fcc9gq3n", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:16.776781Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:21:16.776781Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:21:16.776781Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvtf7ekfbe6sif1ftnab", + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvta7ihe66k1or3f937o", + "threadId": "fvtf7ekfbe6sif1ftnab", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:16.948557Z", + "author": { + "id": "fvt1hbn6kjb6fcc9gq3n", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "GetMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvtf7ekfbe6sif1ftnab", + "messageId": "fvta7ihe66k1or3f937o" + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvta7ihe66k1or3f937o", + "threadId": "fvtf7ekfbe6sif1ftnab", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:16.948557Z", + "author": { + "id": "fvt1hbn6kjb6fcc9gq3n", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtf7ekfbe6sif1ftnab" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_messages/test_message_list.gprc.json b/tests/assistants/cassettes/test_messages/test_message_list.gprc.json new file mode 100644 index 0000000..b8520a1 --- /dev/null +++ b/tests/assistants/cassettes/test_messages/test_message_list.gprc.json @@ -0,0 +1,1079 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt2928lvg5duaaof2u1", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt5mc6hk9firr6e4t2u", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.424985Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:21:17.424985Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:21:17.424985Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt6hbgr05noppbhh206", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.591066Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtsak5gskutq70qc09t", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.758950Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtms0d1mniv128anjkd", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.919751Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt3pk4mle80udbj6oti", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.106210Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtmib59msrndg4bt80q", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.255192Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt3pbn6ahscdhgp1cai", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.395015Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtu73f7kcmmo6srkkf9", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.511772Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtiik3ume2rcfldsftf", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.621174Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtnllhllqi0te46jag9", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.790934Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1", + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtvpua4a7b0ktnh26v5", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.931261Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "ListMessagesRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1" + } + }, + "response_stream": [ + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtvpua4a7b0ktnh26v5", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.931261Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtnllhllqi0te46jag9", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.790934Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtiik3ume2rcfldsftf", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.621174Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtu73f7kcmmo6srkkf9", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.511772Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt3pbn6ahscdhgp1cai", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.395015Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtmib59msrndg4bt80q", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.255192Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt3pk4mle80udbj6oti", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:18.106210Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtms0d1mniv128anjkd", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.919751Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtsak5gskutq70qc09t", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.758950Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt6hbgr05noppbhh206", + "threadId": "fvt2928lvg5duaaof2u1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:21:17.591066Z", + "author": { + "id": "fvt5mc6hk9firr6e4t2u", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + } + ] + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt2928lvg5duaaof2u1" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread.gprc.json b/tests/assistants/cassettes/test_threads/test_thread.gprc.json new file mode 100644 index 0000000..fe2e953 --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread.gprc.json @@ -0,0 +1,522 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt4ml2bm1o0jcdm6fgc", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt3ca45s341b4uk493l", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:26.678841Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:26.678841Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:26.678841Z" + } + } + }, + { + "request": { + "cls": "UpdateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt4ml2bm1o0jcdm6fgc", + "updateMask": "name,description,labels", + "name": "name" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt4ml2bm1o0jcdm6fgc", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "defaultMessageAuthorId": "fvt3ca45s341b4uk493l", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:26.678841Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:26.802136Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:26.678841Z" + } + } + }, + { + "request": { + "cls": "UpdateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt4ml2bm1o0jcdm6fgc", + "updateMask": "name,description,labels", + "description": "description" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt4ml2bm1o0jcdm6fgc", + "folderId": "b1ghsjum2v37c2un8h64", + "description": "description", + "defaultMessageAuthorId": "fvt3ca45s341b4uk493l", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:26.678841Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:26.884395Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:26.678841Z" + } + } + }, + { + "request": { + "cls": "UpdateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt4ml2bm1o0jcdm6fgc", + "updateMask": "name,description,labels", + "labels": { + "foo": "bar" + } + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt4ml2bm1o0jcdm6fgc", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt3ca45s341b4uk493l", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:26.678841Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:26.941843Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:26.678841Z", + "labels": { + "foo": "bar" + } + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt4ml2bm1o0jcdm6fgc" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread_deleted.gprc.json b/tests/assistants/cassettes/test_threads/test_thread_deleted.gprc.json new file mode 100644 index 0000000..1b57430 --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread_deleted.gprc.json @@ -0,0 +1,428 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtiles2t90gc4qdlpp8", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtvpb1tken27o68a4oh", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:31.513531Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:31.513531Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:31.513531Z" + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtiles2t90gc4qdlpp8" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread_get.gprc.json b/tests/assistants/cassettes/test_threads/test_thread_get.gprc.json new file mode 100644 index 0000000..b8d920e --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread_get.gprc.json @@ -0,0 +1,455 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt38goak3v9voiq79qp", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt4ger7jja52vqjp6so", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:27.354267Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:27.354267Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:27.354267Z" + } + } + }, + { + "request": { + "cls": "GetThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt38goak3v9voiq79qp" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt38goak3v9voiq79qp", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt4ger7jja52vqjp6so", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:27.354267Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:27.354267Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:27.354267Z" + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt38goak3v9voiq79qp" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread_list.gprc.json b/tests/assistants/cassettes/test_threads/test_thread_list.gprc.json new file mode 100644 index 0000000..94f7d6d --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread_list.gprc.json @@ -0,0 +1,1000 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt2ne2e05r93ecovmur", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0", + "defaultMessageAuthorId": "fvtahidds245ks5tmpim", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:27.874638Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:27.874638Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:27.874638Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtpigno8f1m09fqf6fe", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1", + "defaultMessageAuthorId": "fvtka01k3a41e4j4cml2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.096497Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.096497Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.096497Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtl9vfngmgeuubqail9", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2", + "defaultMessageAuthorId": "fvtpcejtv9rt9o0k7fst", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.314690Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.314690Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.314690Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt3k5shbpa9skf22rma", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3", + "defaultMessageAuthorId": "fvthla3u68q7dig1eul7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.489848Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.489848Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.489848Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt65fdgis7oprr9364j", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4", + "defaultMessageAuthorId": "fvtpuse9j48nulmep81g", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.724861Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.724861Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.724861Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtp0euavo6iu0fr4otu", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5", + "defaultMessageAuthorId": "fvt2geb258nu9pbcgg1g", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.944916Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.944916Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.944916Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt1npn6ka0b2ptn64js", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6", + "defaultMessageAuthorId": "fvth89u9cisei37uo02a", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.102969Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.102969Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.102969Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvthp957c2snp16qo159", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7", + "defaultMessageAuthorId": "fvttpvg5cpc4qgfap85m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.278990Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.278990Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.278990Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtt5m9epknbe3vf3bii", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8", + "defaultMessageAuthorId": "fvt2k8tv283np2uispic", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.437724Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.437724Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.437724Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt4d5itg7o2bk3d52i0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9", + "defaultMessageAuthorId": "fvt6rge6noak0ur21jo0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.654235Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.654235Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.654235Z" + } + } + }, + { + "request": { + "cls": "ListThreadsRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "ListThreadsResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threads": [ + { + "id": "fvt4d5itg7o2bk3d52i0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9", + "defaultMessageAuthorId": "fvt6rge6noak0ur21jo0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.654235Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.654235Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.654235Z" + }, + { + "id": "fvtt5m9epknbe3vf3bii", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8", + "defaultMessageAuthorId": "fvt2k8tv283np2uispic", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.437724Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.437724Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.437724Z" + }, + { + "id": "fvthp957c2snp16qo159", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7", + "defaultMessageAuthorId": "fvttpvg5cpc4qgfap85m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.278990Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.278990Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.278990Z" + }, + { + "id": "fvt1npn6ka0b2ptn64js", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6", + "defaultMessageAuthorId": "fvth89u9cisei37uo02a", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:29.102969Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:29.102969Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:29.102969Z" + }, + { + "id": "fvtp0euavo6iu0fr4otu", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5", + "defaultMessageAuthorId": "fvt2geb258nu9pbcgg1g", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.944916Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.944916Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.944916Z" + }, + { + "id": "fvt65fdgis7oprr9364j", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4", + "defaultMessageAuthorId": "fvtpuse9j48nulmep81g", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.724861Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.724861Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.724861Z" + }, + { + "id": "fvt3k5shbpa9skf22rma", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3", + "defaultMessageAuthorId": "fvthla3u68q7dig1eul7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.489848Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.489848Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.489848Z" + }, + { + "id": "fvtl9vfngmgeuubqail9", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2", + "defaultMessageAuthorId": "fvtpcejtv9rt9o0k7fst", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.314690Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.314690Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.314690Z" + }, + { + "id": "fvtpigno8f1m09fqf6fe", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1", + "defaultMessageAuthorId": "fvtka01k3a41e4j4cml2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:28.096497Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:28.096497Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:28.096497Z" + }, + { + "id": "fvt2ne2e05r93ecovmur", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0", + "defaultMessageAuthorId": "fvtahidds245ks5tmpim", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:27.874638Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:27.874638Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:27.874638Z" + } + ], + "nextPageToken": "MjAyNC0xMC0wOVQxODozNjoyNy44NzQ2MzhAZnZ0Mm5lMmUwNXI5M2Vjb3ZtdXI=" + } + } + }, + { + "request": { + "cls": "ListThreadsRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageToken": "MjAyNC0xMC0wOVQxODozNjoyNy44NzQ2MzhAZnZ0Mm5lMmUwNXI5M2Vjb3ZtdXI=" + } + }, + "response": { + "cls": "ListThreadsResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt4d5itg7o2bk3d52i0" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtt5m9epknbe3vf3bii" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvthp957c2snp16qo159" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt1npn6ka0b2ptn64js" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtp0euavo6iu0fr4otu" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt65fdgis7oprr9364j" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt3k5shbpa9skf22rma" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtl9vfngmgeuubqail9" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtpigno8f1m09fqf6fe" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt2ne2e05r93ecovmur" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread_read_write.gprc.json b/tests/assistants/cassettes/test_threads/test_thread_read_write.gprc.json new file mode 100644 index 0000000..eea50bf --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread_read_write.gprc.json @@ -0,0 +1,1079 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt7mme21l8lu07p0hoi", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtot60lo6c5ogugu07d", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:31.959021Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-09T18:36:31.959021Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-16T18:36:31.959021Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvth5b1k6s88gngqlls8", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.124823Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtt9aimgbrtd8qp604g", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.226732Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt5584uhc61fosde284", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.374973Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvttldeqnir5ddvi6ki1", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.547134Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt187kk4apjhrislkho", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.714853Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtu581oe9oou8neslqs", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.816126Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt90fot6nukuvhpuv18", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.954538Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtb8pn9tgcbviu1f74d", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.116569Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt0duqrv4aecr2ee80p", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.283660Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi", + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtgsonf7gucnnpgmta6", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.447131Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "ListMessagesRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi" + } + }, + "response_stream": [ + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtgsonf7gucnnpgmta6", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.447131Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "9" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt0duqrv4aecr2ee80p", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.283660Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "8" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtb8pn9tgcbviu1f74d", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:33.116569Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "7" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt90fot6nukuvhpuv18", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.954538Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "6" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtu581oe9oou8neslqs", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.816126Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "5" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt187kk4apjhrislkho", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.714853Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "4" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvttldeqnir5ddvi6ki1", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.547134Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "3" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt5584uhc61fosde284", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.374973Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "2" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtt9aimgbrtd8qp604g", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.226732Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "1" + } + } + ] + } + } + }, + { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvth5b1k6s88gngqlls8", + "threadId": "fvt7mme21l8lu07p0hoi", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-09T18:36:32.124823Z", + "author": { + "id": "fvtot60lo6c5ogugu07d", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "0" + } + } + ] + } + } + } + ] + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt7mme21l8lu07p0hoi" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_messages.py b/tests/assistants/test_messages.py new file mode 100644 index 0000000..9892728 --- /dev/null +++ b/tests/assistants/test_messages.py @@ -0,0 +1,60 @@ +# pylint: disable=protected-access +from __future__ import annotations + +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_message(async_sdk): + thread = await async_sdk.threads.create() + + message = await async_sdk._messages.create( + "foo", + thread_id=thread.id, + labels={'foo': 'bar'}, + ) + + assert message.parts == ['foo'] + assert message.labels == {'foo': 'bar'} + assert message.thread_id == thread.id + assert message.text == 'foo' + assert message.author.role == 'USER' + + await thread.delete() + + +@pytest.mark.allow_grpc +async def test_message_get(async_sdk): + thread = await async_sdk.threads.create() + message = await async_sdk._messages.create( + "foo", + thread_id=thread.id + ) + + second_message = await async_sdk._messages.get(message_id=message.id, thread_id=thread.id) + + assert message.id == second_message.id + + # I hope is temporary + assert message is not second_message + + await thread.delete() + + +@pytest.mark.allow_grpc +async def test_message_list(async_sdk): + thread = await async_sdk.threads.create() + + for i in range(10): + await async_sdk._messages.create( + str(i), + thread_id=thread.id + ) + messages = [f async for f in async_sdk._messages.list(thread_id=thread.id)] + for i, message in enumerate(messages): + assert message.parts[0] == str(9 - i) + + await thread.delete() diff --git a/tests/assistants/test_threads.py b/tests/assistants/test_threads.py new file mode 100644 index 0000000..82bf25a --- /dev/null +++ b/tests/assistants/test_threads.py @@ -0,0 +1,85 @@ +# pylint: disable=protected-access +from __future__ import annotations + +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_thread(async_sdk): + thread = await async_sdk.threads.create() + + for field, value in ( + ('name', 'name'), + ('description', 'description'), + ('labels', {'foo': 'bar'}), + ): + assert getattr(thread, field) is None + + new_thread = await thread.update( + **{field: value} + ) + assert new_thread is thread + + assert getattr(thread, field) == value + + await thread.delete() + + +@pytest.mark.allow_grpc +async def test_thread_get(async_sdk): + thread = await async_sdk.threads.create() + + second_thread = await async_sdk.threads.get(thread.id) + + assert thread.id == second_thread.id + + # I hope is temporary + assert thread is not second_thread + + await thread.delete() + + +@pytest.mark.allow_grpc +async def test_thread_list(async_sdk): + for i in range(10): + await async_sdk.threads.create(name=f"t{i}") + + threads = [f async for f in async_sdk.threads.list()] + thread_names = {t.name for t in threads} + assert thread_names.issuperset({f"t{i}" for i in range(10)}) + + for thread in threads: + await thread.delete() + + +@pytest.mark.allow_grpc +async def test_thread_deleted(async_sdk): + thread = await async_sdk.threads.create() + await thread.delete() + + for method in ('delete', 'update'): + with pytest.raises(ValueError): + await getattr(thread, method)() + + with pytest.raises(ValueError): + await thread.write('foo') + + with pytest.raises(ValueError): + async for _ in thread.read(): + pass + + +@pytest.mark.allow_grpc +async def test_thread_read_write(async_sdk): + thread = await async_sdk.threads.create() + for i in range(10): + await thread.write(str(i)) + messages = [f async for f in thread.read()] + + for i, message in enumerate(messages): + assert message.parts[0] == str(9 - i) + + await thread.delete() diff --git a/tests/conftest.py b/tests/conftest.py index bb1a941..2695b53 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -142,7 +142,8 @@ def fixture_async_sdk( auth=auth, retry_policy=retry_policy, service_map={ - 'ai-files': 'assistant.api.cloud.yandex.net' + 'ai-files': 'assistant.api.cloud.yandex.net', + 'ai-assistants': 'assistant.api.cloud.yandex.net', } ) if test_client: From 2324c06cd5c4c00de84454ebf2c9fa45791732e6 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Tue, 15 Oct 2024 14:34:49 +0200 Subject: [PATCH 04/13] Add expiration mechanic for all assistant-related services (#5) --- examples/async/assistants/files.py | 7 +- examples/async/assistants/threads.py | 5 +- src/yandex_cloud_ml_sdk/_files/domain.py | 15 +- src/yandex_cloud_ml_sdk/_files/file.py | 27 +- src/yandex_cloud_ml_sdk/_threads/domain.py | 11 +- src/yandex_cloud_ml_sdk/_threads/thread.py | 26 +- src/yandex_cloud_ml_sdk/_types/expiration.py | 77 +++ .../test_files/test_file_expiration.gprc.json | 537 ++++++++++++++++++ .../test_thread_expiration.gprc.json | 535 +++++++++++++++++ tests/assistants/test_files.py | 26 + tests/assistants/test_threads.py | 26 + tests/types/test_expiration.py | 53 ++ 12 files changed, 1336 insertions(+), 9 deletions(-) create mode 100644 src/yandex_cloud_ml_sdk/_types/expiration.py create mode 100644 tests/assistants/cassettes/test_files/test_file_expiration.gprc.json create mode 100644 tests/assistants/cassettes/test_threads/test_thread_expiration.gprc.json create mode 100644 tests/types/test_expiration.py diff --git a/examples/async/assistants/files.py b/examples/async/assistants/files.py index 6c3ddea..a48ed93 100755 --- a/examples/async/assistants/files.py +++ b/examples/async/assistants/files.py @@ -17,12 +17,15 @@ async def main() -> None: ) path = pathlib.Path(__file__).parent / 'example_file' - file = await sdk.files.upload(path) + file = await sdk.files.upload(path, ttl_days=5, expiration_policy="static") + print(file) - await file.update(name='foo') + await file.update(name='foo', ttl_days=9) + print(file) second = await sdk.files.get(file.id) + await second.update(name='foo', expiration_policy='since_last_active') print(second) diff --git a/examples/async/assistants/threads.py b/examples/async/assistants/threads.py index 390bfe8..3f57482 100755 --- a/examples/async/assistants/threads.py +++ b/examples/async/assistants/threads.py @@ -15,8 +15,11 @@ async def main() -> None: } ) - thread = await sdk.threads.create(name='foo') + thread = await sdk.threads.create(name='foo', ttl_days=5, expiration_policy="static") + print(thread) second = await sdk.threads.get(thread.id) + await second.update(ttl_days=9) + print(second) await thread.write("content") await second.write("content2") diff --git a/src/yandex_cloud_ml_sdk/_files/domain.py b/src/yandex_cloud_ml_sdk/_files/domain.py index 38dfdfa..63bbf94 100644 --- a/src/yandex_cloud_ml_sdk/_files/domain.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -10,7 +10,8 @@ from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub from yandex_cloud_ml_sdk._types.domain import BaseDomain -from yandex_cloud_ml_sdk._types.misc import UNDEFINED, PathLike, UndefinedOr, coerce_path, get_defined_value +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, PathLike, UndefinedOr, coerce_path, get_defined_value, is_defined from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .file import AsyncFile, BaseFile, File @@ -29,14 +30,22 @@ async def _upload_bytes( description: UndefinedOr[str] = UNDEFINED, mime_type: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> FileTypeT: + if is_defined(ttl_days) != is_defined(expiration_policy): + raise ValueError("ttl_days and expiration policy must be both defined either undefined") + + expiration_config = ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) + request = CreateFileRequest( folder_id=self._folder_id, name=get_defined_value(name, ''), description=get_defined_value(description, ''), mime_type=get_defined_value(mime_type, ''), labels=get_defined_value(labels, {}), + expiration_config=expiration_config.to_proto(), content=data, ) @@ -58,6 +67,8 @@ async def _upload( description: UndefinedOr[str] = UNDEFINED, mime_type: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> FileTypeT: path = coerce_path(path) @@ -67,6 +78,8 @@ async def _upload( description=description, mime_type=mime_type, labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, timeout=timeout ) diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py index a8d434a..5cd1143 100644 --- a/src/yandex_cloud_ml_sdk/_files/file.py +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -3,6 +3,7 @@ import dataclasses from datetime import datetime +from typing import Any import httpx from typing_extensions import Self @@ -12,6 +13,7 @@ ) from yandex.cloud.ai.files.v1.file_service_pb2_grpc import FileServiceStub +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync @@ -19,6 +21,17 @@ @dataclasses.dataclass(frozen=True) class BaseFile(BaseDeleteableResource): + expiration_config: ExpirationConfig + + @classmethod + def _kwargs_from_message(cls, proto: ProtoFile) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto) + kwargs['expiration_config'] = ExpirationConfig.coerce( + ttl_days=proto.expiration_config.ttl_days, + expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] + ) + return kwargs + @safe_on_delete async def _get_url( self, @@ -44,23 +57,33 @@ async def _update( name: UndefinedOr[str] = UNDEFINED, description: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> Self: + # pylint: disable=too-many-locals name_ = get_defined_value(name, '') description_ = get_defined_value(description, '') labels_ = get_defined_value(labels, {}) + expiration_config = ExpirationConfig.coerce( + ttl_days=ttl_days, + expiration_policy=expiration_policy + ) + request = UpdateFileRequest( file_id=self.id, name=name_, description=description_, labels=labels_, + expiration_config=expiration_config.to_proto() ) - for key, value in ( ('name', name_), ('description', description_), - ('labels', labels_) + ('labels', labels_), + ('expiration_config.ttl_days', expiration_config.ttl_days), + ('expiration_config.expiration_policy', expiration_config.expiration_policy), ): if value is not None: request.update_mask.paths.append(key) diff --git a/src/yandex_cloud_ml_sdk/_threads/domain.py b/src/yandex_cloud_ml_sdk/_threads/domain.py index a968868..84a1a4d 100644 --- a/src/yandex_cloud_ml_sdk/_threads/domain.py +++ b/src/yandex_cloud_ml_sdk/_threads/domain.py @@ -10,7 +10,8 @@ from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2_grpc import ThreadServiceStub from yandex_cloud_ml_sdk._types.domain import BaseDomain -from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .thread import AsyncThread, BaseThread, Thread @@ -27,13 +28,21 @@ async def _create( name: UndefinedOr[str] = UNDEFINED, description: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> ThreadTypeT: + if is_defined(ttl_days) != is_defined(expiration_policy): + raise ValueError("ttl_days and expiration policy must be both defined either undefined") + + expiration_config = ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) + request = CreateThreadRequest( folder_id=self._folder_id, name=get_defined_value(name, ''), description=get_defined_value(description, ''), labels=get_defined_value(labels, {}), + expiration_config=expiration_config.to_proto(), ) async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py index 2f027cb..ee1ee12 100644 --- a/src/yandex_cloud_ml_sdk/_threads/thread.py +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import AsyncIterator +from typing import Any, AsyncIterator from typing_extensions import Self from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread @@ -13,6 +13,7 @@ from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2_grpc import ThreadServiceStub from yandex_cloud_ml_sdk._messages.message import Message +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator @@ -20,6 +21,17 @@ @dataclasses.dataclass(frozen=True) class BaseThread(BaseDeleteableResource): + expiration_config: ExpirationConfig + + @classmethod + def _kwargs_from_message(cls, proto: ProtoThread) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto) + kwargs['expiration_config'] = ExpirationConfig.coerce( + ttl_days=proto.expiration_config.ttl_days, + expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] + ) + return kwargs + @safe_on_delete async def _update( self, @@ -27,23 +39,33 @@ async def _update( name: UndefinedOr[str] = UNDEFINED, description: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> Self: + # pylint: disable=too-many-locals name_ = get_defined_value(name, '') description_ = get_defined_value(description, '') labels_ = get_defined_value(labels, {}) + expiration_config = ExpirationConfig.coerce( + ttl_days=ttl_days, + expiration_policy=expiration_policy + ) request = UpdateThreadRequest( thread_id=self.id, name=name_, description=description_, labels=labels_, + expiration_config=expiration_config.to_proto(), ) for key, value in ( ('name', name_), ('description', description_), - ('labels', labels_) + ('labels', labels_), + ('expiration_config.ttl_days', expiration_config.ttl_days), + ('expiration_config.expiration_policy', expiration_config.expiration_policy), ): if value is not None: request.update_mask.paths.append(key) diff --git a/src/yandex_cloud_ml_sdk/_types/expiration.py b/src/yandex_cloud_ml_sdk/_types/expiration.py new file mode 100644 index 0000000..e6e0316 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_types/expiration.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum +from typing import Literal, Union + +# pylint: disable-next=no-name-in-module +from yandex.cloud.ai.common.common_pb2 import ExpirationConfig as ExpirationConfigProto + +from .misc import UndefinedOr, get_defined_value + + +class ExpirationPolicy(Enum): + STATIC = ExpirationConfigProto.STATIC + SINCE_LAST_ACTIVE = ExpirationConfigProto.SINCE_LAST_ACTIVE + + @classmethod + def coerce(cls, value: ExpirationPolicyAlias) -> ExpirationPolicy: + if isinstance(value, cls): + return value + if isinstance(value, int): + return cls(value) + if isinstance(value, str): + if member := cls.__members__.get(value.upper()): + return member + raise ValueError(f'wrong value {value} for use as an alisas for {cls}') + raise TypeError(f'wrong type for use as an alias for {cls}') + + def to_proto(self) -> int: + return { + self.STATIC: ExpirationConfigProto.STATIC, + self.SINCE_LAST_ACTIVE: ExpirationConfigProto.SINCE_LAST_ACTIVE + }[self] # type: ignore[index] + + +ExpirationPolicyAlias = Union[ + ExpirationPolicy, + Literal[1, 2], + Literal['STATIC', 'SINCE_LAST_ACTIVE'], + Literal['static', 'since_last_active'], +] + + +@dataclass(frozen=True) +class ExpirationConfig: + ttl_days: int | None = None + expiration_policy: ExpirationPolicy | None = None + + @classmethod + def coerce( + cls, + ttl_days: UndefinedOr[int], + expiration_policy: UndefinedOr[ExpirationPolicyAlias] + ) -> ExpirationConfig: + ttl_days_ = get_defined_value(ttl_days, None) + expiration_policy_raw = get_defined_value(expiration_policy, None) + expiration_policy_: ExpirationPolicy | None = None + if expiration_policy_raw is not None: + expiration_policy_ = ExpirationPolicy.coerce(expiration_policy_raw) # type: ignore[arg-type] + + return cls( + ttl_days=ttl_days_, + expiration_policy=expiration_policy_ + ) + + def to_proto(self) -> ExpirationConfigProto | None: + if not self.expiration_policy and not self.ttl_days: + return None + + expiration_policy = 0 + if self.expiration_policy: + expiration_policy = self.expiration_policy.to_proto() + + return ExpirationConfigProto( + expiration_policy=expiration_policy, # type: ignore[arg-type] + ttl_days=self.ttl_days or 0 + ) diff --git a/tests/assistants/cassettes/test_files/test_file_expiration.gprc.json b/tests/assistants/cassettes/test_files/test_file_expiration.gprc.json new file mode 100644 index 0000000..7637455 --- /dev/null +++ b/tests/assistants/cassettes/test_files/test_file_expiration.gprc.json @@ -0,0 +1,537 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtccn26if22sl7kvedk", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:46:01.742672Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:46:01.742672Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-21T17:46:01.742672Z" + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + } + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtk8m8l3hib8tjtq32a", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:46:01.890912Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:46:01.890912Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + }, + "expiresAt": "2024-10-19T17:46:01.890912Z" + } + } + }, + { + "request": { + "cls": "UpdateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtccn26if22sl7kvedk", + "updateMask": "name,description,labels,expirationConfig.ttlDays", + "expirationConfig": { + "ttlDays": "3" + } + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtccn26if22sl7kvedk", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:46:01.742672Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:46:02.061415Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "3" + }, + "expiresAt": "2024-10-21T17:46:01.742672Z" + } + } + }, + { + "request": { + "cls": "UpdateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtccn26if22sl7kvedk", + "updateMask": "name,description,labels,expirationConfig.expirationPolicy", + "expirationConfig": { + "expirationPolicy": "STATIC" + } + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtccn26if22sl7kvedk", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:46:01.742672Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:46:02.122500Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "3" + }, + "expiresAt": "2024-10-21T17:46:01.742672Z" + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtccn26if22sl7kvedk" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtk8m8l3hib8tjtq32a" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_threads/test_thread_expiration.gprc.json b/tests/assistants/cassettes/test_threads/test_thread_expiration.gprc.json new file mode 100644 index 0000000..5e5d6ba --- /dev/null +++ b/tests/assistants/cassettes/test_threads/test_thread_expiration.gprc.json @@ -0,0 +1,535 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt86o5tu0uu31m7a8nv", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtjeg66tovh08ddiohu", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:47:52.145136Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:47:52.145136Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-21T17:47:52.145136Z" + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + } + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtkne8mfqndbmdrsglf", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtmf29ejb6hbm7dj54a", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:47:52.324656Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:47:52.324656Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + }, + "expiresAt": "2024-10-19T17:47:52.324656Z" + } + } + }, + { + "request": { + "cls": "UpdateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt86o5tu0uu31m7a8nv", + "updateMask": "name,description,labels,expirationConfig.ttlDays", + "expirationConfig": { + "ttlDays": "3" + } + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt86o5tu0uu31m7a8nv", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtjeg66tovh08ddiohu", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:47:52.145136Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:47:52.426485Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "3" + }, + "expiresAt": "2024-10-21T17:47:52.145136Z" + } + } + }, + { + "request": { + "cls": "UpdateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt86o5tu0uu31m7a8nv", + "updateMask": "name,description,labels,expirationConfig.expirationPolicy", + "expirationConfig": { + "expirationPolicy": "STATIC" + } + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt86o5tu0uu31m7a8nv", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtjeg66tovh08ddiohu", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-14T17:47:52.145136Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-14T17:47:52.495294Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "3" + }, + "expiresAt": "2024-10-21T17:47:52.145136Z" + } + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt86o5tu0uu31m7a8nv" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtkne8mfqndbmdrsglf" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_files.py b/tests/assistants/test_files.py index 82375c7..bd57fec 100644 --- a/tests/assistants/test_files.py +++ b/tests/assistants/test_files.py @@ -94,3 +94,29 @@ async def test_file_list(async_sdk, tmp_path): for file in files: await file.delete() + + +@pytest.mark.allow_grpc +async def test_file_expiration(async_sdk, test_file_path): + with pytest.raises(ValueError): + await async_sdk.files.upload(test_file_path, ttl_days=5) + + with pytest.raises(ValueError): + await async_sdk.files.upload(test_file_path, expiration_policy='static') + + file = await async_sdk.files.upload(test_file_path) + assert file.expiration_config.ttl_days == 7 + assert file.expiration_config.expiration_policy.name == 'SINCE_LAST_ACTIVE' + + file2 = await async_sdk.files.upload(test_file_path, ttl_days=5, expiration_policy="static") + assert file2.expiration_config.ttl_days == 5 + assert file2.expiration_config.expiration_policy.name == 'STATIC' + + await file.update(ttl_days=3) + assert file.expiration_config.ttl_days == 3 + + await file.update(expiration_policy='static') + assert file.expiration_config.expiration_policy.name == 'STATIC' + + await file.delete() + await file2.delete() diff --git a/tests/assistants/test_threads.py b/tests/assistants/test_threads.py index 82bf25a..30b95ed 100644 --- a/tests/assistants/test_threads.py +++ b/tests/assistants/test_threads.py @@ -83,3 +83,29 @@ async def test_thread_read_write(async_sdk): assert message.parts[0] == str(9 - i) await thread.delete() + + +@pytest.mark.allow_grpc +async def test_thread_expiration(async_sdk): + with pytest.raises(ValueError): + await async_sdk.threads.create(ttl_days=5) + + with pytest.raises(ValueError): + await async_sdk.threads.create(expiration_policy='static') + + thread = await async_sdk.threads.create() + assert thread.expiration_config.ttl_days == 7 + assert thread.expiration_config.expiration_policy.name == 'SINCE_LAST_ACTIVE' + + thread2 = await async_sdk.threads.create(ttl_days=5, expiration_policy="static") + assert thread2.expiration_config.ttl_days == 5 + assert thread2.expiration_config.expiration_policy.name == 'STATIC' + + await thread.update(ttl_days=3) + assert thread.expiration_config.ttl_days == 3 + + await thread.update(expiration_policy='static') + assert thread.expiration_config.expiration_policy.name == 'STATIC' + + await thread.delete() + await thread2.delete() diff --git a/tests/types/test_expiration.py b/tests/types/test_expiration.py new file mode 100644 index 0000000..1c253e4 --- /dev/null +++ b/tests/types/test_expiration.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import inspect + +import pytest + +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationConfigProto, ExpirationPolicy +from yandex_cloud_ml_sdk._types.misc import UNDEFINED + + +@pytest.mark.parametrize( + "test_input,expected", + [ + ('static', ExpirationConfigProto.STATIC), + ('since_last_active', ExpirationConfigProto.SINCE_LAST_ACTIVE), + ('STATIC', ExpirationConfigProto.STATIC), + ('SINCE_LAST_ACTIVE', ExpirationConfigProto.SINCE_LAST_ACTIVE), + (1, ExpirationConfigProto.STATIC), + (2, ExpirationConfigProto.SINCE_LAST_ACTIVE), + (3, ValueError), + ('foo', ValueError), + ({}, TypeError), + ] +) +def test_expiration_policy(test_input, expected): + if inspect.isclass(expected) and issubclass(expected, Exception): + with pytest.raises(expected): + ExpirationPolicy.coerce(test_input) + else: + assert ExpirationPolicy.coerce(test_input).to_proto() == expected + + +@pytest.mark.parametrize( + "expected,ttl_days,expiration_policy", + [ + (ExpirationConfig(ttl_days=1), 1, UNDEFINED), + (ExpirationConfig(expiration_policy=ExpirationPolicy.STATIC), UNDEFINED, 'static'), + (ExpirationConfig(expiration_policy=ExpirationPolicy.STATIC), UNDEFINED, 'STATIC'), + (ValueError, UNDEFINED, 'foo'), + (ExpirationConfig(expiration_policy=ExpirationPolicy.SINCE_LAST_ACTIVE), + UNDEFINED, ExpirationPolicy.SINCE_LAST_ACTIVE), + (ExpirationConfig(ttl_days=2, expiration_policy=ExpirationPolicy.STATIC), 2, 'static'), + (ExpirationConfig(), UNDEFINED, UNDEFINED), + (TypeError, str, int), + + ], +) +def test_expiration_config(expected, ttl_days, expiration_policy): + if inspect.isclass(expected) and issubclass(expected, Exception): + with pytest.raises(expected): + ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) + else: + assert ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) == expected From 07fd982d2fa485058c85ae46aedd10b1dad58fa2 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 18 Oct 2024 15:39:26 +0200 Subject: [PATCH 05/13] Add assistants service support (#7) --- examples/async/assistants/assistants.py | 41 + .../_assistants/__init__.py | 0 .../_assistants/assistant.py | 224 ++++ src/yandex_cloud_ml_sdk/_assistants/domain.py | 157 +++ src/yandex_cloud_ml_sdk/_assistants/utils.py | 29 + src/yandex_cloud_ml_sdk/_files/file.py | 28 +- src/yandex_cloud_ml_sdk/_messages/message.py | 9 +- src/yandex_cloud_ml_sdk/_models/__init__.py | 4 +- src/yandex_cloud_ml_sdk/_sdk.py | 6 +- src/yandex_cloud_ml_sdk/_threads/thread.py | 29 +- src/yandex_cloud_ml_sdk/_types/model.py | 11 + src/yandex_cloud_ml_sdk/_types/resource.py | 16 +- src/yandex_cloud_ml_sdk/_utils/sync.py | 3 +- .../test_assistants/test_assistant.gprc.json | 912 +++++++++++++ .../test_assistant_deleted.gprc.json | 433 +++++++ .../test_assistant_expiration.gprc.json | 553 ++++++++ .../test_assistant_get.gprc.json | 462 +++++++ .../test_assistant_list.gprc.json | 1140 +++++++++++++++++ .../test_assistant_versions.gprc.json | 599 +++++++++ tests/assistants/test_assistants.py | 159 +++ 20 files changed, 4779 insertions(+), 36 deletions(-) create mode 100755 examples/async/assistants/assistants.py create mode 100644 src/yandex_cloud_ml_sdk/_assistants/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_assistants/assistant.py create mode 100644 src/yandex_cloud_ml_sdk/_assistants/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_assistants/utils.py create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant.gprc.json create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant_deleted.gprc.json create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant_expiration.gprc.json create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant_get.gprc.json create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant_list.gprc.json create mode 100644 tests/assistants/cassettes/test_assistants/test_assistant_versions.gprc.json create mode 100644 tests/assistants/test_assistants.py diff --git a/examples/async/assistants/assistants.py b/examples/async/assistants/assistants.py new file mode 100755 index 0000000..2638162 --- /dev/null +++ b/examples/async/assistants/assistants.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio + +from yandex_cloud_ml_sdk import AsyncYCloudML + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + assistant = await sdk.assistants.create( + 'yandexgpt', + ttl_days=1, + expiration_policy='static', + temperature=0.5, + max_prompt_tokens=50, + ) + assistant2 = await sdk.assistants.get(assistant.id) + print(assistant2) + await assistant2.update(model='yandexgpt-lite', name='foo', max_tokens=5) + print(assistant2) + + async for version in assistant.list_versions(): + print(version) + + async for assistant in sdk.assistants.list(): + print(f"deliting assistant {assistant}") + + await assistant.delete() + + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/src/yandex_cloud_ml_sdk/_assistants/__init__.py b/src/yandex_cloud_ml_sdk/_assistants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_assistants/assistant.py b/src/yandex_cloud_ml_sdk/_assistants/assistant.py new file mode 100644 index 0000000..3fed0de --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_assistants/assistant.py @@ -0,0 +1,224 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +from datetime import datetime +from typing import TYPE_CHECKING, Any, AsyncIterator + +from typing_extensions import Self +from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant +from yandex.cloud.ai.assistants.v1.assistant_service_pb2 import ( + DeleteAssistantRequest, DeleteAssistantResponse, ListAssistantVersionsRequest, ListAssistantVersionsResponse, + UpdateAssistantRequest +) +from yandex.cloud.ai.assistants.v1.assistant_service_pb2_grpc import AssistantServiceStub + +from yandex_cloud_ml_sdk._models.completions.model import BaseGPTModel +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined +from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .utils import get_completion_options, get_prompt_trunctation_options + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +@dataclasses.dataclass(frozen=True) +class BaseAssistant(BaseDeleteableResource): + expiration_config: ExpirationConfig + model: BaseGPTModel + instruction: str | None + max_prompt_tokens: int | None + + @classmethod + def _kwargs_from_message(cls, proto: ProtoAssistant, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) + + model = sdk.models.completions(proto.model_uri) + if max_tokens := proto.completion_options.max_tokens.value: + model = model.configure(max_tokens=max_tokens) + if temperature := proto.completion_options.temperature.value: + model = model.configure(temperature=temperature) + kwargs['model'] = model + + if max_prompt_tokens := proto.prompt_truncation_options.max_prompt_tokens.value: + kwargs['max_prompt_tokens'] = max_prompt_tokens + + kwargs['expiration_config'] = ExpirationConfig.coerce( + ttl_days=proto.expiration_config.ttl_days, + expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] + ) + return kwargs + + # pylint: disable=too-many-arguments + @safe_on_delete + async def _update( + self, + *, + model: UndefinedOr[str | BaseGPTModel] = UNDEFINED, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + # pylint: disable=too-many-locals + expiration_config = ExpirationConfig.coerce( + ttl_days=ttl_days, + expiration_policy=expiration_policy + ) + + model_uri: str | None = None + model_temperature: float | None = self.model.config.temperature + model_max_tokens: int | None = self.model.config.max_tokens + + if is_defined(model): + if isinstance(model, str): + model_uri = self._sdk.models.completions(model).uri + elif isinstance(model, BaseGPTModel): + model_uri = model.uri + model_temperature = model.config.temperature + model_max_tokens = model.config.max_tokens + else: + raise TypeError('model argument must be str, GPTModel object either undefined') + + model_temperature = get_defined_value(temperature, model_temperature) + model_max_tokens = get_defined_value(max_tokens, model_max_tokens) + + request = UpdateAssistantRequest( + assistant_id=self.id, + name=get_defined_value(name, ''), + description=get_defined_value(description, ''), + labels=get_defined_value(labels, {}), + instruction=get_defined_value(instruction, ''), + expiration_config=expiration_config.to_proto(), + prompt_truncation_options=get_prompt_trunctation_options( + max_prompt_tokens=get_defined_value(max_prompt_tokens, None) + ), + completion_options=get_completion_options( + temperature=model_temperature, + max_tokens=model_max_tokens + ) + ) + if model_uri: + request.model_uri = model_uri + + self._fill_update_mask( + request.update_mask, + { + 'name': name, + 'description': description, + 'labels': labels, + 'expiration_config.ttl_days': ttl_days, + 'expiration_config.expiration_policy': expiration_policy, + 'instruction': instruction, + 'model_uri': model_uri, + 'completion_options.temperature': model_temperature, + 'completion_options.max_tokens': model_max_tokens, + 'prompt_truncation_options.max_prompt_tokens': max_prompt_tokens, + } + ) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Update, + request, + timeout=timeout, + expected_type=ProtoAssistant, + ) + self._update_from_proto(response) + + return self + + @safe_on_delete + async def _delete( + self, + *, + timeout: float = 60, + ) -> None: + request = DeleteAssistantRequest(assistant_id=self.id) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + await self._client.call_service( + stub.Delete, + request, + timeout=timeout, + expected_type=DeleteAssistantResponse, + ) + object.__setattr__(self, '_deleted', True) + + async def _list_versions( + self, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AssistantVersion]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + while True: + request = ListAssistantVersionsRequest( + assistant_id=self.id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.ListVersions, + request, + timeout=timeout, + expected_type=ListAssistantVersionsResponse, + ) + for version in response.versions: + yield AssistantVersion( + id=version.id, + assistant=ReadOnlyAssistant._from_proto( + sdk=self._sdk, + proto=version.assistant + ), + update_mask=tuple(a for a in version.update_mask.paths) + ) + + if not response.versions: + return + + page_token_ = response.next_page_token + + +@dataclasses.dataclass(frozen=True) +class ReadOnlyAssistant(BaseAssistant): + name: str | None + description: str | None + created_by: str + created_at: datetime + updated_by: str + updated_at: datetime + expires_at: datetime + labels: dict[str, str] | None + + +@dataclasses.dataclass(frozen=True) +class AssistantVersion: + id: str + assistant: ReadOnlyAssistant + update_mask: tuple[str, ...] + + +class AsyncAssistant(ReadOnlyAssistant): + update = ReadOnlyAssistant._update + delete = ReadOnlyAssistant._delete + list_versions = ReadOnlyAssistant._list_versions + + +class Assistant(ReadOnlyAssistant): + update = run_sync(ReadOnlyAssistant._update) + delete = run_sync(ReadOnlyAssistant._delete) + list_versions = run_sync_generator(ReadOnlyAssistant._list_versions) diff --git a/src/yandex_cloud_ml_sdk/_assistants/domain.py b/src/yandex_cloud_ml_sdk/_assistants/domain.py new file mode 100644 index 0000000..94d4323 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_assistants/domain.py @@ -0,0 +1,157 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import AsyncIterator, Generic, TypeVar + +from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant +from yandex.cloud.ai.assistants.v1.assistant_service_pb2 import ( + CreateAssistantRequest, GetAssistantRequest, ListAssistantsRequest, ListAssistantsResponse +) +from yandex.cloud.ai.assistants.v1.assistant_service_pb2_grpc import AssistantServiceStub + +from yandex_cloud_ml_sdk._models.completions.model import BaseGPTModel +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .assistant import Assistant, AsyncAssistant, BaseAssistant +from .utils import get_completion_options, get_prompt_trunctation_options + +AssistantTypeT = TypeVar('AssistantTypeT', bound=BaseAssistant) + + +class BaseAssistants(BaseDomain, Generic[AssistantTypeT]): + _assistant_impl: type[AssistantTypeT] + + # pylint: disable=too-many-arguments + async def _create( + self, + model: str | BaseGPTModel, + *, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AssistantTypeT: + # pylint: disable=too-many-locals + if is_defined(ttl_days) != is_defined(expiration_policy): + raise ValueError("ttl_days and expiration policy must be both defined either undefined") + + expiration_config = ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) + + model_uri: str = '' + model_temperature: float | None = None + model_max_tokens: int | None = None + if isinstance(model, str): + model_uri = self._sdk.models.completions(model).uri + elif isinstance(model, BaseGPTModel): + model_uri = model.uri + model_temperature = model.config.temperature + model_max_tokens = model.config.max_tokens + else: + raise TypeError('model argument must be str, GPTModel object either undefined') + + model_temperature = get_defined_value(temperature, model_temperature) + model_max_tokens = get_defined_value(max_tokens, model_max_tokens) + + request = CreateAssistantRequest( + folder_id=self._folder_id, + name=get_defined_value(name, ''), + description=get_defined_value(description, ''), + labels=get_defined_value(labels, {}), + expiration_config=expiration_config.to_proto(), + instruction=get_defined_value(instruction, ''), + prompt_truncation_options=get_prompt_trunctation_options( + max_prompt_tokens=get_defined_value(max_prompt_tokens, None) + ), + model_uri=model_uri, + completion_options=get_completion_options( + temperature=model_temperature, + max_tokens=model_max_tokens + ) + ) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoAssistant, + ) + + return self._assistant_impl._from_proto(proto=response, sdk=self._sdk) + + async def _get( + self, + assistant_id: str, + *, + timeout: float = 60, + ) -> AssistantTypeT: + # TODO: we need a global per-sdk cache on ids to rule out + # possibility we have two Assistants with same ids but different fields + request = GetAssistantRequest(assistant_id=assistant_id) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoAssistant, + ) + + return self._assistant_impl._from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AssistantTypeT]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: + while True: + request = ListAssistantsRequest( + folder_id=self._folder_id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListAssistantsResponse, + ) + for assistant_proto in response.assistants: + yield self._assistant_impl._from_proto(proto=assistant_proto, sdk=self._sdk) + + if not response.assistants: + return + + page_token_ = response.next_page_token + + +class AsyncAssistants(BaseAssistants[AsyncAssistant]): + _assistant_impl = AsyncAssistant + + get = BaseAssistants._get + create = BaseAssistants._create + list = BaseAssistants._list + + +class Assistants(BaseAssistants[Assistant]): + _assistant_impl = Assistant + + get = run_sync(BaseAssistants._get) + create = run_sync(BaseAssistants._create) + list = run_sync_generator(BaseAssistants._list) diff --git a/src/yandex_cloud_ml_sdk/_assistants/utils.py b/src/yandex_cloud_ml_sdk/_assistants/utils.py new file mode 100644 index 0000000..3fd659e --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_assistants/utils.py @@ -0,0 +1,29 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +from yandex.cloud.ai.assistants.v1.common_pb2 import CompletionOptions, PromptTruncationOptions + + +def get_completion_options( + *, + temperature: float | None, + max_tokens: int | None, +) -> CompletionOptions: + options = CompletionOptions() + if temperature is not None: + options.temperature.value = temperature + if max_tokens is not None: + options.max_tokens.value = max_tokens + + return options + + +def get_prompt_trunctation_options( + *, + max_prompt_tokens: int | None +) -> PromptTruncationOptions: + options = PromptTruncationOptions() + if max_prompt_tokens is not None: + options.max_prompt_tokens.value = max_prompt_tokens + + return options diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py index 5cd1143..d94ef95 100644 --- a/src/yandex_cloud_ml_sdk/_files/file.py +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import Any +from typing import TYPE_CHECKING, Any import httpx from typing_extensions import Self @@ -18,14 +18,17 @@ from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + @dataclasses.dataclass(frozen=True) class BaseFile(BaseDeleteableResource): expiration_config: ExpirationConfig @classmethod - def _kwargs_from_message(cls, proto: ProtoFile) -> dict[str, Any]: # type: ignore[override] - kwargs = super()._kwargs_from_message(proto) + def _kwargs_from_message(cls, proto: ProtoFile, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) kwargs['expiration_config'] = ExpirationConfig.coerce( ttl_days=proto.expiration_config.ttl_days, expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] @@ -78,15 +81,16 @@ async def _update( labels=labels_, expiration_config=expiration_config.to_proto() ) - for key, value in ( - ('name', name_), - ('description', description_), - ('labels', labels_), - ('expiration_config.ttl_days', expiration_config.ttl_days), - ('expiration_config.expiration_policy', expiration_config.expiration_policy), - ): - if value is not None: - request.update_mask.paths.append(key) + self._fill_update_mask( + request.update_mask, + { + 'name': name, + 'description': description, + 'labels': labels, + 'expiration_config.ttl_days': ttl_days, + 'expiration_config.expiration_policy': expiration_policy + } + ) async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: response = await self._client.call_service( diff --git a/src/yandex_cloud_ml_sdk/_messages/message.py b/src/yandex_cloud_ml_sdk/_messages/message.py index 29f440b..002ab92 100644 --- a/src/yandex_cloud_ml_sdk/_messages/message.py +++ b/src/yandex_cloud_ml_sdk/_messages/message.py @@ -3,12 +3,15 @@ import dataclasses from datetime import datetime -from typing import Any +from typing import TYPE_CHECKING, Any from yandex.cloud.ai.assistants.v1.threads.message_pb2 import Message as ProtoMessage from yandex_cloud_ml_sdk._types.resource import BaseResource +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + @dataclasses.dataclass(frozen=True) class Author: @@ -26,8 +29,8 @@ class Message(BaseResource): author: Author @classmethod - def _kwargs_from_message(cls, proto: ProtoMessage) -> dict[str, Any]: # type: ignore[override] - kwargs = super()._kwargs_from_message(proto) + def _kwargs_from_message(cls, proto: ProtoMessage, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) parts: list[Any] = [] for part in proto.content.content: diff --git a/src/yandex_cloud_ml_sdk/_models/__init__.py b/src/yandex_cloud_ml_sdk/_models/__init__.py index 00d85c4..05365f9 100644 --- a/src/yandex_cloud_ml_sdk/_models/__init__.py +++ b/src/yandex_cloud_ml_sdk/_models/__init__.py @@ -7,7 +7,7 @@ from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.function import BaseFunction -from .completions.function import AsyncCompletions, Completions +from .completions.function import AsyncCompletions, BaseCompletions, Completions from .text_classifiers.function import AsyncTextClassifiers, TextClassifiers from .text_embeddings.function import AsyncTextEmbeddings, TextEmbeddings @@ -16,6 +16,8 @@ class BaseModels(BaseDomain): + completions: BaseCompletions + def __init__(self, name: str, sdk: BaseSDK): super().__init__(name=name, sdk=sdk) self._init_functions() diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 5def565..278cb24 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -9,11 +9,12 @@ from get_annotations import get_annotations from grpc import aio +from ._assistants.domain import Assistants, AsyncAssistants from ._auth import BaseAuth from ._client import AsyncCloudClient from ._files.domain import AsyncFiles, Files from ._messages.domain import AsyncMessages, BaseMessages, Messages -from ._models import AsyncModels, Models +from ._models import AsyncModels, BaseModels, Models from ._retry import RetryPolicy from ._threads.domain import AsyncThreads, Threads from ._types.domain import BaseDomain @@ -22,6 +23,7 @@ class BaseSDK: _messages: BaseMessages + models: BaseModels def __init__( self, @@ -134,6 +136,7 @@ class AsyncYCloudML(BaseSDK): models: AsyncModels files: AsyncFiles threads: AsyncThreads + assistants: AsyncAssistants _messages: AsyncMessages @@ -141,4 +144,5 @@ class YCloudML(BaseSDK): models: Models files: Files threads: Threads + assistants: Assistants _messages: Messages diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py index ee1ee12..8b2115c 100644 --- a/src/yandex_cloud_ml_sdk/_threads/thread.py +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import Any, AsyncIterator +from typing import TYPE_CHECKING, Any, AsyncIterator from typing_extensions import Self from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread @@ -18,14 +18,17 @@ from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + @dataclasses.dataclass(frozen=True) class BaseThread(BaseDeleteableResource): expiration_config: ExpirationConfig @classmethod - def _kwargs_from_message(cls, proto: ProtoThread) -> dict[str, Any]: # type: ignore[override] - kwargs = super()._kwargs_from_message(proto) + def _kwargs_from_message(cls, proto: ProtoThread, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) kwargs['expiration_config'] = ExpirationConfig.coerce( ttl_days=proto.expiration_config.ttl_days, expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] @@ -60,15 +63,16 @@ async def _update( expiration_config=expiration_config.to_proto(), ) - for key, value in ( - ('name', name_), - ('description', description_), - ('labels', labels_), - ('expiration_config.ttl_days', expiration_config.ttl_days), - ('expiration_config.expiration_policy', expiration_config.expiration_policy), - ): - if value is not None: - request.update_mask.paths.append(key) + self._fill_update_mask( + request.update_mask, + { + 'name': name, + 'description': description, + 'labels': labels, + 'expiration_config.ttl_days': ttl_days, + 'expiration_config.expiration_policy': expiration_policy + } + ) async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: response = await self._client.call_service( @@ -136,7 +140,6 @@ async def _read( class RichThread(BaseThread): name: str | None description: str | None - mime_type: str created_by: str created_at: datetime updated_by: str diff --git a/src/yandex_cloud_ml_sdk/_types/model.py b/src/yandex_cloud_ml_sdk/_types/model.py index 8b5ab31..e80d9d1 100644 --- a/src/yandex_cloud_ml_sdk/_types/model.py +++ b/src/yandex_cloud_ml_sdk/_types/model.py @@ -35,6 +35,14 @@ def __init__( self._uri = uri self._config = config if config else self._config_type() + @property + def uri(self) -> str: + return self._uri + + @property + def config(self) -> ConfigTypeT: + return self._config + @property def _client(self): return self._sdk._client @@ -51,6 +59,9 @@ def configure(self, **kwargs) -> Self: config=replace(self._config, **kwargs), ) + def __repr__(self) -> str: + return f'{self.__class__.__name__}(uri={self._uri}, config={self._config})' + class ModelSyncMixin(BaseModel[ConfigTypeT, ResultTypeT]): @abc.abstractmethod diff --git a/src/yandex_cloud_ml_sdk/_types/resource.py b/src/yandex_cloud_ml_sdk/_types/resource.py index ef293d0..f5e481b 100644 --- a/src/yandex_cloud_ml_sdk/_types/resource.py +++ b/src/yandex_cloud_ml_sdk/_types/resource.py @@ -5,11 +5,14 @@ import functools from typing import TYPE_CHECKING, Any, Awaitable, Callable, TypeVar +from google.protobuf.field_mask_pb2 import FieldMask # pylint: disable=no-name-in-module from google.protobuf.message import Message from typing_extensions import Concatenate, ParamSpec, Self from yandex_cloud_ml_sdk._utils.proto import proto_to_dict +from .misc import is_defined + if TYPE_CHECKING: from yandex_cloud_ml_sdk._client import AsyncCloudClient from yandex_cloud_ml_sdk._sdk import BaseSDK @@ -26,7 +29,7 @@ def _client(self) -> AsyncCloudClient: return self._sdk._client @classmethod - def _kwargs_from_message(cls, proto: Message) -> dict[str, Any]: + def _kwargs_from_message(cls, proto: Message, sdk: BaseSDK) -> dict[str, Any]: # pylint: disable=unused-argument fields = dataclasses.fields(cls) data = proto_to_dict(proto) kwargs = {} @@ -43,17 +46,22 @@ def _kwargs_from_message(cls, proto: Message) -> dict[str, Any]: def _from_proto(cls, *, sdk: BaseSDK, proto: Message) -> Self: return cls( _sdk=sdk, - **cls._kwargs_from_message(proto), + **cls._kwargs_from_message(proto, sdk=sdk), ) def _update_from_proto(self, proto: Message) -> Self: # We want to Resource to be a immutable, but also we need # to maintain a inner status after updating and such - kwargs = self._kwargs_from_message(proto) + kwargs = self._kwargs_from_message(proto, sdk=self._sdk) for key, value in kwargs.items(): object.__setattr__(self, key, value) return self + def _fill_update_mask(self, mask: FieldMask, fields: dict[str, Any]) -> None: + for key, value in fields.items(): + if is_defined(value) and value is not None: + mask.paths.append(key) + @dataclasses.dataclass(frozen=True) class BaseDeleteableResource(BaseResource): @@ -66,7 +74,7 @@ def _from_proto(cls, *, sdk: BaseSDK, proto: Message) -> Self: _sdk=sdk, _lock=asyncio.Lock(), _deleted=False, - **cls._kwargs_from_message(proto), + **cls._kwargs_from_message(proto, sdk=sdk), ) diff --git a/src/yandex_cloud_ml_sdk/_utils/sync.py b/src/yandex_cloud_ml_sdk/_utils/sync.py index 4094fef..ca3f607 100644 --- a/src/yandex_cloud_ml_sdk/_utils/sync.py +++ b/src/yandex_cloud_ml_sdk/_utils/sync.py @@ -88,8 +88,7 @@ def run_from(runner: Callable[[Awaitable[T]], Any]) -> Iterator[T]: def run_sync_generator(coro: Callable[..., AsyncIterator[T]]) -> Callable[..., Iterator[T]]: """Wraps async iterator function into a usual iterator function that blocks on every cycle. """ - if not inspect.isasyncgenfunction(coro): - raise AssertionError + assert inspect.isasyncgenfunction(coro) @wraps(coro) def wrapped(self: Any, *args: Any, **kwargs: Any) -> Any: diff --git a/tests/assistants/cassettes/test_assistants/test_assistant.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant.gprc.json new file mode 100644 index 0000000..e15d76b --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant.gprc.json @@ -0,0 +1,912 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.088251Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6", + "updateMask": "name", + "name": "name", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.157631Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6", + "updateMask": "description", + "description": "description", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.211072Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6", + "updateMask": "labels", + "labels": { + "foo": "bar" + }, + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.254723Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "labels": { + "foo": "bar" + }, + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6", + "updateMask": "instruction", + "instruction": "instruction", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.311873Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "labels": { + "foo": "bar" + }, + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "instruction": "instruction", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6", + "updateMask": "promptTruncationOptions.maxPromptTokens", + "promptTruncationOptions": { + "maxPromptTokens": "50" + }, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.344166Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "labels": { + "foo": "bar" + }, + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "instruction": "instruction", + "promptTruncationOptions": { + "maxPromptTokens": "50" + }, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.409661Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "modelUri", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.487720Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "modelUri", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.529484Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "completionOptions.temperature", + "promptTruncationOptions": {}, + "completionOptions": { + "temperature": 0.5 + } + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.580629Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "temperature": 0.5 + } + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "completionOptions.temperature,completionOptions.maxTokens", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "50", + "temperature": 0.5 + } + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.611221Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "50", + "temperature": 0.5 + } + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "modelUri,completionOptions.temperature,completionOptions.maxTokens", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "100", + "temperature": 1.0 + } + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.688336Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "100", + "temperature": 1.0 + } + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "modelUri,completionOptions.temperature,completionOptions.maxTokens", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "100", + "temperature": 0.1 + } + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.759069Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "100", + "temperature": 0.1 + } + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98", + "updateMask": "modelUri,completionOptions.temperature,completionOptions.maxTokens", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "10", + "temperature": 1.0 + } + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtfe055nlui23ld5e98", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.409661Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.803370Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.409661Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt-lite/latest", + "promptTruncationOptions": {}, + "completionOptions": { + "maxTokens": "10", + "temperature": 1.0 + } + } + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtfe055nlui23ld5e98" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_assistants/test_assistant_deleted.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant_deleted.gprc.json new file mode 100644 index 0000000..9a067ec --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant_deleted.gprc.json @@ -0,0 +1,433 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtgcoh22a7pp63gvtr1", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.287190Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.287190Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.287190Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtgcoh22a7pp63gvtr1" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_assistants/test_assistant_expiration.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant_expiration.gprc.json new file mode 100644 index 0000000..a45b1ef --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant_expiration.gprc.json @@ -0,0 +1,553 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtr7d8aogne68ao5t52", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.566484Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.566484Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.566484Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + }, + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtbod8cpm2efjjfrp3d", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.640184Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.640184Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "5" + }, + "expiresAt": "2024-10-22T17:38:39.640184Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtr7d8aogne68ao5t52", + "updateMask": "expirationConfig.ttlDays", + "expirationConfig": { + "ttlDays": "3" + }, + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtr7d8aogne68ao5t52", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.566484Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.699723Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "3" + }, + "expiresAt": "2024-10-24T17:38:39.566484Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtr7d8aogne68ao5t52", + "updateMask": "expirationConfig.expirationPolicy", + "expirationConfig": { + "expirationPolicy": "STATIC" + }, + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtr7d8aogne68ao5t52", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.566484Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.740604Z", + "expirationConfig": { + "expirationPolicy": "STATIC", + "ttlDays": "3" + }, + "expiresAt": "2024-10-24T17:38:39.566484Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtr7d8aogne68ao5t52" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtbod8cpm2efjjfrp3d" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_assistants/test_assistant_get.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant_get.gprc.json new file mode 100644 index 0000000..a242cd4 --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant_get.gprc.json @@ -0,0 +1,462 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtsq3e39081q10e09oc", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.044327Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.044327Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.044327Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "GetAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtsq3e39081q10e09oc" + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtsq3e39081q10e09oc", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.044327Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.044327Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.044327Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtsq3e39081q10e09oc" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_assistants/test_assistant_list.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant_list.gprc.json new file mode 100644 index 0000000..2424f8b --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant_list.gprc.json @@ -0,0 +1,1140 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtp9diig8tnrba3prb4", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.409191Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.409191Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.409191Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtjjfk94qnds0jfkvdj", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.494513Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.494513Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.494513Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtaan54kfsh5lg2t9dq", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.605662Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.605662Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.605662Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvttgd8niv211tmmrv1v", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.721512Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.721512Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.721512Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt9a3lo56futbcqq6mr", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.784022Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.784022Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.784022Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtpa3add866tbupe3lr", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.836900Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.836900Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.836900Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt9jc7grcu0ca1jg44r", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.914821Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.914821Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.914821Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt4ksfr8ksmru165qct", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.051699Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.051699Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.051699Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvttr9koreph0n9ilkp0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.191146Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.191146Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.191146Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtg4m915v83ie1ob8ro", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.239202Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.239202Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.239202Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "ListAssistantsRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "ListAssistantsResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistants": [ + { + "id": "fvtg4m915v83ie1ob8ro", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t9", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.239202Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.239202Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.239202Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvttr9koreph0n9ilkp0", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t8", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.191146Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.191146Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.191146Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvt4ksfr8ksmru165qct", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:38.051699Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:38.051699Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:38.051699Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvt9jc7grcu0ca1jg44r", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t6", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.914821Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.914821Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.914821Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvtpa3add866tbupe3lr", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t5", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.836900Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.836900Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.836900Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvt9a3lo56futbcqq6mr", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t4", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.784022Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.784022Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.784022Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvttgd8niv211tmmrv1v", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t3", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.721512Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.721512Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.721512Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvtaan54kfsh5lg2t9dq", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.605662Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.605662Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.605662Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvtjjfk94qnds0jfkvdj", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.494513Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.494513Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.494513Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvtp9diig8tnrba3prb4", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "t0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:37.409191Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:37.409191Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:37.409191Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + }, + { + "id": "fvt5rn7cnuctlm0u01o6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:36.088251Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:36.344166Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:36.088251Z", + "labels": { + "foo": "bar" + }, + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "instruction": "instruction", + "promptTruncationOptions": { + "maxPromptTokens": "50" + }, + "completionOptions": {} + }, + { + "id": "fvtupnda75r009cf4scm", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "bar", + "description": "baz", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:12.928314Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:13.081336Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:12.928314Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + ], + "nextPageToken": "MjAyNC0xMC0xN1QxNzozODoxMi45MjgzMTRAZnZ0dXBuZGE3NXIwMDljZjRzY20=" + } + } + }, + { + "request": { + "cls": "ListAssistantsRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageToken": "MjAyNC0xMC0xN1QxNzozODoxMi45MjgzMTRAZnZ0dXBuZGE3NXIwMDljZjRzY20=" + } + }, + "response": { + "cls": "ListAssistantsResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtg4m915v83ie1ob8ro" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvttr9koreph0n9ilkp0" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt4ksfr8ksmru165qct" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt9jc7grcu0ca1jg44r" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtpa3add866tbupe3lr" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt9a3lo56futbcqq6mr" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvttgd8niv211tmmrv1v" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtaan54kfsh5lg2t9dq" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtjjfk94qnds0jfkvdj" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtp9diig8tnrba3prb4" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt5rn7cnuctlm0u01o6" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtupnda75r009cf4scm" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_assistants/test_assistant_versions.gprc.json b/tests/assistants/cassettes/test_assistants/test_assistant_versions.gprc.json new file mode 100644 index 0000000..1b27f06 --- /dev/null +++ b/tests/assistants/cassettes/test_assistants/test_assistant_versions.gprc.json @@ -0,0 +1,599 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.962320Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt0642fb77q16vn2eef", + "updateMask": "name", + "name": "foo", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "foo", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:40.022608Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "UpdateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt0642fb77q16vn2eef", + "updateMask": "name,description", + "name": "bar", + "description": "baz", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "bar", + "description": "baz", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:40.078270Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "ListAssistantVersionsRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt0642fb77q16vn2eef" + } + }, + "response": { + "cls": "ListAssistantVersionsResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "versions": [ + { + "id": "fvt4p9ufau23jkq9ec9j", + "updateMask": "name,description", + "assistant": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "bar", + "description": "baz", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:40.078270Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + { + "id": "fvtjaio6bjlmv4kv9h8l", + "updateMask": "name", + "assistant": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "foo", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:40.022608Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + { + "id": "fvtic55o8o5hdc4ibc0l", + "updateMask": "", + "assistant": { + "id": "fvt0642fb77q16vn2eef", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-17T17:38:39.962320Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-17T17:38:39.962320Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-24T17:38:39.962320Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + ], + "nextPageToken": "MjAyNC0xMC0xN1QxNzozODozOS45NjIzMjBAZnZ0aWM1NW84bzVoZGM0aWJjMGw=" + } + } + }, + { + "request": { + "cls": "ListAssistantVersionsRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt0642fb77q16vn2eef", + "pageToken": "MjAyNC0xMC0xN1QxNzozODozOS45NjIzMjBAZnZ0aWM1NW84bzVoZGM0aWJjMGw=" + } + }, + "response": { + "cls": "ListAssistantVersionsResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt0642fb77q16vn2eef" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_assistants.py b/tests/assistants/test_assistants.py new file mode 100644 index 0000000..af5f1b4 --- /dev/null +++ b/tests/assistants/test_assistants.py @@ -0,0 +1,159 @@ +# pylint: disable=protected-access +from __future__ import annotations + +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_assistant(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + + for field, value in ( + ('name', 'name'), + ('description', 'description'), + ('labels', {'foo': 'bar'}), + ('instruction', 'instruction'), + ('max_prompt_tokens', 50), + ): + assert getattr(assistant, field) is None + + new_assistant = await assistant.update( + **{field: value} + ) + assert new_assistant is assistant + + assert getattr(assistant, field) == value + + assistant = await async_sdk.assistants.create('yandexgpt') + model = async_sdk.models.completions('yandexgpt-lite') + + await assistant.update(model=model) + assert '/yandexgpt-lite/' in assistant.model.uri + + await assistant.update(model='yandexgpt') + assert '/yandexgpt/' in assistant.model.uri + + assert assistant.model.config.temperature is None + assert assistant.model.config.max_tokens is None + + await assistant.update(temperature=0.5) + assert assistant.model.config.temperature == 0.5 + assert assistant.model.config.max_tokens is None + + await assistant.update(max_tokens=50) + assert assistant.model.config.temperature == 0.5 + assert assistant.model.config.max_tokens == 50 + + model = model.configure(max_tokens=100, temperature=1) + + await assistant.update(model=model) + assert '/yandexgpt-lite/' in assistant.model.uri + assert assistant.model.config.temperature == 1 + assert assistant.model.config.max_tokens == 100 + + await assistant.update(model=model, temperature=0.1) + assert '/yandexgpt-lite/' in assistant.model.uri + assert assistant.model.config.temperature == 0.1 + assert assistant.model.config.max_tokens == 100 + + await assistant.update(model=model, max_tokens=10) + assert '/yandexgpt-lite/' in assistant.model.uri + assert assistant.model.config.temperature == 1 + assert assistant.model.config.max_tokens == 10 + + await assistant.delete() + + +@pytest.mark.allow_grpc +async def test_assistant_get(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + + second_assistant = await async_sdk.assistants.get(assistant.id) + + assert assistant.id == second_assistant.id + + # I hope is temporary + assert assistant is not second_assistant + + await assistant.delete() + + +@pytest.mark.allow_grpc +async def test_assistant_list(async_sdk): + for i in range(10): + await async_sdk.assistants.create(model='yandexgpt', name=f"t{i}") + + assistants = [f async for f in async_sdk.assistants.list()] + assistant_names = {t.name for t in assistants} + assert assistant_names.issuperset({f"t{i}" for i in range(10)}) + + for assistant in assistants: + await assistant.delete() + + +@pytest.mark.allow_grpc +async def test_assistant_deleted(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + await assistant.delete() + + for method in ('delete', 'update'): + with pytest.raises(ValueError): + await getattr(assistant, method)() + + with pytest.raises(ValueError): + await assistant.delete('foo') + + +@pytest.mark.allow_grpc +async def test_assistant_expiration(async_sdk): + with pytest.raises(ValueError): + await async_sdk.assistants.create(model='yandexgpt', ttl_days=5) + + with pytest.raises(ValueError): + await async_sdk.assistants.create('yandexgpt', expiration_policy='static') + + assistant = await async_sdk.assistants.create('yandexgpt') + assert assistant.expiration_config.ttl_days == 7 + assert assistant.expiration_config.expiration_policy.name == 'SINCE_LAST_ACTIVE' + + assistant2 = await async_sdk.assistants.create('yandexgpt', ttl_days=5, expiration_policy="static") + assert assistant2.expiration_config.ttl_days == 5 + assert assistant2.expiration_config.expiration_policy.name == 'STATIC' + + await assistant.update(ttl_days=3) + assert assistant.expiration_config.ttl_days == 3 + + await assistant.update(expiration_policy='static') + assert assistant.expiration_config.expiration_policy.name == 'STATIC' + + await assistant.delete() + await assistant2.delete() + + +@pytest.mark.allow_grpc +async def test_assistant_versions(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + + await assistant.update(name='foo') + await assistant.update(name='bar', description='baz') + + versions = [v async for v in assistant.list_versions()] + + assert len(versions) == 3 + + assert versions[0].assistant.name == 'bar' + assert versions[0].assistant.description == 'baz' + assert versions[0].update_mask == ('name', 'description') + + assert versions[1].assistant.name == 'foo' + assert versions[1].assistant.description is None + assert versions[1].update_mask == ('name', ) + + assert versions[2].assistant.name is None + assert versions[2].assistant.description is None + assert versions[2].update_mask == () + + await assistant.delete() From c4d38720b12dcb41e91aa3fe157709eee11b498e Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 25 Oct 2024 19:14:29 +0200 Subject: [PATCH 06/13] Assistants run (#8) --- examples/async/assistants/runs.py | 56 ++ pyproject.toml | 2 +- .../_assistants/assistant.py | 249 ++++- src/yandex_cloud_ml_sdk/_assistants/domain.py | 6 +- src/yandex_cloud_ml_sdk/_messages/message.py | 43 +- .../_models/completions/model.py | 2 +- .../_models/completions/result.py | 7 +- .../_models/text_classifiers/model.py | 4 +- .../_models/text_classifiers/result.py | 8 +- .../_models/text_embeddings/model.py | 2 +- .../_models/text_embeddings/result.py | 7 +- src/yandex_cloud_ml_sdk/_runs/__init__.py | 0 src/yandex_cloud_ml_sdk/_runs/domain.py | 175 ++++ src/yandex_cloud_ml_sdk/_runs/result.py | 124 +++ src/yandex_cloud_ml_sdk/_runs/run.py | 117 +++ src/yandex_cloud_ml_sdk/_runs/status.py | 76 ++ src/yandex_cloud_ml_sdk/_sdk.py | 13 +- src/yandex_cloud_ml_sdk/_threads/domain.py | 6 +- src/yandex_cloud_ml_sdk/_threads/thread.py | 5 +- src/yandex_cloud_ml_sdk/_types/operation.py | 62 +- src/yandex_cloud_ml_sdk/_types/result.py | 7 +- src/yandex_cloud_ml_sdk/_utils/proto.py | 17 +- .../cassettes/test_run/test_run.gprc.json | 734 ++++++++++++++ .../test_run/test_run_methods.gprc.json | 934 ++++++++++++++++++ .../test_run/test_run_stream.gprc.json | 754 ++++++++++++++ tests/assistants/test_assistants.py | 2 +- tests/assistants/test_messages.py | 2 +- tests/assistants/test_run.py | 97 ++ 28 files changed, 3436 insertions(+), 75 deletions(-) create mode 100755 examples/async/assistants/runs.py create mode 100644 src/yandex_cloud_ml_sdk/_runs/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_runs/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_runs/result.py create mode 100644 src/yandex_cloud_ml_sdk/_runs/run.py create mode 100644 src/yandex_cloud_ml_sdk/_runs/status.py create mode 100644 tests/assistants/cassettes/test_run/test_run.gprc.json create mode 100644 tests/assistants/cassettes/test_run/test_run_methods.gprc.json create mode 100644 tests/assistants/cassettes/test_run/test_run_stream.gprc.json create mode 100644 tests/assistants/test_run.py diff --git a/examples/async/assistants/runs.py b/examples/async/assistants/runs.py new file mode 100755 index 0000000..d31c17f --- /dev/null +++ b/examples/async/assistants/runs.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio + +from yandex_cloud_ml_sdk import AsyncYCloudML + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + assistant = await sdk.assistants.create( + 'yandexgpt', + temperature=0.5, + max_prompt_tokens=50, + ttl_days=6, + expiration_policy='static', + ) + print('assistant: ', assistant) + + thread = await sdk.threads.create( + name='foo', + ttl_days=6, + expiration_policy='static', + ) + print('thread: ', thread) + + await thread.write("hi! how are you") + run = await assistant.run_stream(thread) + async for event in run: + print('event:', event) + + await thread.write("how is your name?") + run = await assistant.run(thread) + result = await run + print('run result:', result) + + run = await sdk.runs.get_last_by_thread(thread) + print('last run:', run) + + async for run in sdk.runs.list(page_size=10): + print('run:', run) + + async for assistant in sdk.assistants.list(): + await assistant.delete() + + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/pyproject.toml b/pyproject.toml index 80adf3b..4bb6ea2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -234,7 +234,7 @@ valid-classmethod-first-arg="cls" valid-metaclass-classmethod-first-arg="cls" [tool.pylint.'DESIGN'] -max-args=10 +max-args=15 max-attributes=15 max-bool-expr=5 max-branches=12 diff --git a/src/yandex_cloud_ml_sdk/_assistants/assistant.py b/src/yandex_cloud_ml_sdk/_assistants/assistant.py index 3fed0de..e0b5434 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/assistant.py +++ b/src/yandex_cloud_ml_sdk/_assistants/assistant.py @@ -1,9 +1,9 @@ -# pylint: disable=no-name-in-module +# pylint: disable=no-name-in-module,protected-access from __future__ import annotations import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any, AsyncIterator +from typing import TYPE_CHECKING, Any, AsyncIterator, Generic, Iterator, TypeVar from typing_extensions import Self from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant @@ -14,10 +14,12 @@ from yandex.cloud.ai.assistants.v1.assistant_service_pb2_grpc import AssistantServiceStub from yandex_cloud_ml_sdk._models.completions.model import BaseGPTModel +from yandex_cloud_ml_sdk._runs.run import AsyncRun, Run, RunTypeT +from yandex_cloud_ml_sdk._threads.thread import AsyncThread, Thread, ThreadTypeT from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete -from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator +from yandex_cloud_ml_sdk._utils.sync import run_sync_generator_impl, run_sync_impl from .utils import get_completion_options, get_prompt_trunctation_options @@ -26,7 +28,7 @@ @dataclasses.dataclass(frozen=True) -class BaseAssistant(BaseDeleteableResource): +class BaseAssistant(BaseDeleteableResource, Generic[RunTypeT, ThreadTypeT]): expiration_config: ExpirationConfig model: BaseGPTModel instruction: str | None @@ -192,9 +194,67 @@ async def _list_versions( page_token_ = response.next_page_token + @safe_on_delete + async def _run_impl( + self, + thread: str | ThreadTypeT, + *, + stream: bool, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> RunTypeT: + return await self._sdk.runs._create( + assistant=self, + thread=thread, + stream=stream, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout, + ) + + async def _run( + self, + thread: str | ThreadTypeT, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> RunTypeT: + return await self._run_impl( + thread=thread, + stream=False, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout, + ) + + async def _run_stream( + self, + thread: str | ThreadTypeT, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> RunTypeT: + return await self._run_impl( + thread=thread, + stream=True, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout, + ) + + @dataclasses.dataclass(frozen=True) -class ReadOnlyAssistant(BaseAssistant): +class ReadOnlyAssistant(BaseAssistant[RunTypeT, ThreadTypeT]): name: str | None description: str | None created_by: str @@ -212,13 +272,176 @@ class AssistantVersion: update_mask: tuple[str, ...] -class AsyncAssistant(ReadOnlyAssistant): - update = ReadOnlyAssistant._update - delete = ReadOnlyAssistant._delete - list_versions = ReadOnlyAssistant._list_versions +class AsyncAssistant(ReadOnlyAssistant[AsyncRun, AsyncThread]): + async def update( + self, + *, + model: UndefinedOr[str | BaseGPTModel] = UNDEFINED, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return await self._update( + model=model, + temperature=temperature, + max_tokens=max_tokens, + instruction=instruction, + max_prompt_tokens=max_prompt_tokens, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + async def delete( + self, + *, + timeout: float = 60, + ) -> None: + await self._delete(timeout=timeout) + + async def list_versions( + self, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AssistantVersion]: + async for version in self._list_versions( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ): + yield version + + async def run( + self, + thread: str | AsyncThread, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> AsyncRun: + return await self._run( + thread=thread, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout + ) + + async def run_stream( + self, + thread: str | AsyncThread, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> AsyncRun: + return await self._run_stream( + thread=thread, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout + ) + + +class Assistant(ReadOnlyAssistant[Run, Thread]): + def update( + self, + *, + model: UndefinedOr[str | BaseGPTModel] = UNDEFINED, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return run_sync_impl(self._update( + model=model, + temperature=temperature, + max_tokens=max_tokens, + instruction=instruction, + max_prompt_tokens=max_prompt_tokens, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ), self._sdk) + + def delete( + self, + *, + timeout: float = 60, + ) -> None: + run_sync_impl(self._delete(timeout=timeout), self._sdk) + + def list_versions( + self, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[AssistantVersion]: + yield from run_sync_generator_impl( + self._list_versions( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ), + self._sdk + ) + + def run( + self, + thread: str | Thread, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> Run: + return run_sync_impl(self._run( + thread=thread, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout + ), self._sdk) + + def run_stream( + self, + thread: str | Thread, + *, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> Run: + return run_sync_impl(self._run_stream( + thread=thread, + custom_temperature=custom_temperature, + custom_max_tokens=custom_max_tokens, + custom_max_prompt_tokens=custom_max_prompt_tokens, + timeout=timeout + ), self._sdk) -class Assistant(ReadOnlyAssistant): - update = run_sync(ReadOnlyAssistant._update) - delete = run_sync(ReadOnlyAssistant._delete) - list_versions = run_sync_generator(ReadOnlyAssistant._list_versions) +AssistantTypeT = TypeVar('AssistantTypeT', bound=BaseAssistant) diff --git a/src/yandex_cloud_ml_sdk/_assistants/domain.py b/src/yandex_cloud_ml_sdk/_assistants/domain.py index 94d4323..ca07762 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/domain.py +++ b/src/yandex_cloud_ml_sdk/_assistants/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic, TypeVar +from typing import AsyncIterator, Generic from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant from yandex.cloud.ai.assistants.v1.assistant_service_pb2 import ( @@ -15,11 +15,9 @@ from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator -from .assistant import Assistant, AsyncAssistant, BaseAssistant +from .assistant import Assistant, AssistantTypeT, AsyncAssistant from .utils import get_completion_options, get_prompt_trunctation_options -AssistantTypeT = TypeVar('AssistantTypeT', bound=BaseAssistant) - class BaseAssistants(BaseDomain, Generic[AssistantTypeT]): _assistant_impl: type[AssistantTypeT] diff --git a/src/yandex_cloud_ml_sdk/_messages/message.py b/src/yandex_cloud_ml_sdk/_messages/message.py index 002ab92..823fe28 100644 --- a/src/yandex_cloud_ml_sdk/_messages/message.py +++ b/src/yandex_cloud_ml_sdk/_messages/message.py @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any from yandex.cloud.ai.assistants.v1.threads.message_pb2 import Message as ProtoMessage +from yandex.cloud.ai.assistants.v1.threads.message_pb2 import MessageContent from yandex_cloud_ml_sdk._types.resource import BaseResource @@ -20,12 +21,23 @@ class Author: @dataclasses.dataclass(frozen=True) -class Message(BaseResource): +class BaseMessage(BaseResource): + parts: tuple[Any, ...] + + @property + def text(self): + return '\n'.join( + part for part in self.parts + if isinstance(part, str) + ) + + +@dataclasses.dataclass(frozen=True) +class Message(BaseMessage): thread_id: str created_by: str created_at: datetime labels: dict[str, str] | None - parts: list[Any] author: Author @classmethod @@ -41,7 +53,7 @@ def _kwargs_from_message(cls, proto: ProtoMessage, sdk: BaseSDK) -> dict[str, An 'messages with non-string content are not supported in this SDK version' ) - kwargs['parts'] = parts + kwargs['parts'] = tuple(parts) kwargs['author'] = Author( role=proto.author.role, id=proto.author.id @@ -49,9 +61,22 @@ def _kwargs_from_message(cls, proto: ProtoMessage, sdk: BaseSDK) -> dict[str, An return kwargs - @property - def text(self): - return '\n'.join( - part for part in self.parts - if isinstance(part, str) - ) + +@dataclasses.dataclass(frozen=True) +class PartialMessage(BaseMessage): + @classmethod + def _kwargs_from_message(cls, proto: MessageContent, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) + parts: list[Any] = [] + + # NB: it takes content from another structure other than Message + for part in proto.content: + if hasattr(part, 'text'): + parts.append(part.text.content) + else: + raise NotImplementedError( + 'messages with non-string content are not supported in this SDK version' + ) + + kwargs['parts'] = tuple(parts) + return kwargs diff --git a/src/yandex_cloud_ml_sdk/_models/completions/model.py b/src/yandex_cloud_ml_sdk/_models/completions/model.py index 6b8b8a2..eab2896 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/model.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/model.py @@ -84,7 +84,7 @@ async def _run_sync_impl( timeout=timeout, expected_type=CompletionResponse, ): - yield GPTModelResult._from_proto(response) + yield GPTModelResult._from_proto(response, sdk=self._sdk) # something like mypy or pylint asking me to put this return here return diff --git a/src/yandex_cloud_ml_sdk/_models/completions/result.py b/src/yandex_cloud_ml_sdk/_models/completions/result.py index d64f208..3ffa2d4 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/result.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/result.py @@ -3,7 +3,7 @@ from collections.abc import Sequence from dataclasses import dataclass from enum import Enum -from typing import overload +from typing import TYPE_CHECKING, overload from typing_extensions import Self # pylint: disable-next=no-name-in-module @@ -13,6 +13,9 @@ from .message import TextMessage +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + @dataclass(frozen=True) class Usage: @@ -52,7 +55,7 @@ class GPTModelResult(BaseResult[CompletionResponse], Sequence): model_version: str @classmethod - def _from_proto(cls, message: CompletionResponse) -> Self: + def _from_proto(cls, message: CompletionResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument alternatives = tuple( Alternative( role=alternative.message.role, diff --git a/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py b/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py index 335aaef..028bbf5 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py +++ b/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py @@ -58,7 +58,7 @@ async def _run_classify( timeout=timeout, expected_type=TextClassificationResponse, ) - return TextClassifiersModelResult._from_proto(response) + return TextClassifiersModelResult._from_proto(response, sdk=self._sdk) async def _run_few_shot( self, @@ -100,7 +100,7 @@ async def _run_few_shot( timeout=timeout, expected_type=FewShotTextClassificationResponse, ) - return FewShotTextClassifiersModelResult._from_proto(response) + return FewShotTextClassifiersModelResult._from_proto(response, sdk=self._sdk) class AsyncTextClassifiersModel(BaseTextClassifiersModel): diff --git a/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py b/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py index 33469fc..401ad53 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py +++ b/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass -from typing import TypeVar, overload +from typing import TYPE_CHECKING, TypeVar, overload from typing_extensions import Self # pylint: disable-next=no-name-in-module @@ -14,6 +14,10 @@ from .types import TextClassificationLabel +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + TextClassificationResponseT = TypeVar( 'TextClassificationResponseT', TextClassificationResponse, @@ -27,7 +31,7 @@ class TextClassifiersModelResultBase(BaseResult[TextClassificationResponseT], Se model_version: str @classmethod - def _from_proto(cls, message: TextClassificationResponseT) -> Self: + def _from_proto(cls, message: TextClassificationResponseT, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument predictions = tuple( TextClassificationLabel( label=p.label, diff --git a/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py b/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py index 9d0f3d5..43a08fd 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py +++ b/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py @@ -48,7 +48,7 @@ async def _run( timeout=timeout, expected_type=TextEmbeddingResponse, ) - return TextEmbeddingsModelResult._from_proto(response) + return TextEmbeddingsModelResult._from_proto(response, sdk=self._sdk) class AsyncTextEmbeddingsModel(BaseTextEmbeddingsModel): diff --git a/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py b/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py index 9e254e5..72e69c8 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py +++ b/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass -from typing import overload +from typing import TYPE_CHECKING, overload from typing_extensions import Self # pylint: disable-next=no-name-in-module @@ -10,6 +10,9 @@ from yandex_cloud_ml_sdk._types.result import BaseResult +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + @dataclass(frozen=True) class TextEmbeddingsModelResult(BaseResult[TextEmbeddingResponse], Sequence): @@ -20,7 +23,7 @@ class TextEmbeddingsModelResult(BaseResult[TextEmbeddingResponse], Sequence): model_version: str @classmethod - def _from_proto(cls, message: TextEmbeddingResponse) -> Self: + def _from_proto(cls, message: TextEmbeddingResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument return cls( embedding=tuple(message.embedding), num_tokens=message.num_tokens, diff --git a/src/yandex_cloud_ml_sdk/_runs/__init__.py b/src/yandex_cloud_ml_sdk/_runs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_runs/domain.py b/src/yandex_cloud_ml_sdk/_runs/domain.py new file mode 100644 index 0000000..04b53eb --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_runs/domain.py @@ -0,0 +1,175 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import AsyncIterator, Generic + +from yandex.cloud.ai.assistants.v1.runs.run_pb2 import Run as ProtoRun +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import ( + CreateRunRequest, GetLastRunByThreadRequest, GetRunRequest, ListRunsRequest, ListRunsResponse +) +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2_grpc import RunServiceStub + +from yandex_cloud_ml_sdk._assistants.assistant import Assistant, AssistantTypeT, AsyncAssistant, BaseAssistant +from yandex_cloud_ml_sdk._assistants.utils import get_completion_options, get_prompt_trunctation_options +from yandex_cloud_ml_sdk._threads.thread import AsyncThread, BaseThread, Thread, ThreadTypeT +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .run import AsyncRun, Run, RunTypeT + + +class BaseRuns(BaseDomain, Generic[RunTypeT, AssistantTypeT, ThreadTypeT]): + _run_impl: type[RunTypeT] + _assistant_impl: type[AssistantTypeT] + _thread_impl: type[ThreadTypeT] + + async def _create( + self, + assistant: str | AssistantTypeT, + thread: str | ThreadTypeT, + *, + stream: bool, + custom_temperature: UndefinedOr[float] = UNDEFINED, + custom_max_tokens: UndefinedOr[int] = UNDEFINED, + custom_max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + timeout: float = 60, + ) -> RunTypeT: + assistant_id: str + if isinstance(assistant, str): + assistant_id = assistant + elif isinstance(assistant, BaseAssistant): + assistant_id = assistant.id + else: + raise TypeError('assistant parameter must be a str either Assistant instance') + + thread_id: str + if isinstance(thread, str): + thread_id = thread + elif isinstance(thread, BaseThread): + thread_id = thread.id + else: + raise TypeError('thread parameter must be a str either Thread instance') + + request = CreateRunRequest( + assistant_id=assistant_id, + thread_id=thread_id, + custom_completion_options=get_completion_options( + temperature=get_defined_value(custom_temperature, None), + max_tokens=get_defined_value(custom_max_tokens, None), + ), + custom_prompt_truncation_options=get_prompt_trunctation_options( + max_prompt_tokens=get_defined_value(custom_max_prompt_tokens, None), + ), + stream=stream, + ) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoRun, + ) + + return self._run_impl._from_proto(proto=response, sdk=self._sdk) + + async def _get( + self, + run_id: str, + *, + timeout: float = 60, + ) -> RunTypeT: + # TODO: we need a global per-sdk cache on ids to rule out + # possibility we have two Runs with same ids but different fields + request = GetRunRequest(run_id=run_id) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoRun, + ) + + return self._run_impl._from_proto(proto=response, sdk=self._sdk) + + async def _get_last_by_thread( + self, + thread: str | ThreadTypeT, + *, + timeout: float = 60 + ) -> RunTypeT: + thread_id: str + if isinstance(thread, str): + thread_id = thread + elif isinstance(thread, BaseThread): + thread_id = thread.id + else: + raise TypeError('thread parameter must be a str either Thread instance') + + request = GetLastRunByThreadRequest(thread_id=thread_id) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.GetLastByThread, + request, + timeout=timeout, + expected_type=ProtoRun, + ) + + return self._run_impl._from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[RunTypeT]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + while True: + request = ListRunsRequest( + folder_id=self._folder_id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListRunsResponse, + ) + for run_proto in response.runs: + yield self._run_impl._from_proto(proto=run_proto, sdk=self._sdk) + + if not response.runs: + return + + page_token_ = response.next_page_token + + +class AsyncRuns(BaseRuns[AsyncRun, AsyncAssistant, AsyncThread]): + _run_impl = AsyncRun + _assistant_impl = AsyncAssistant + _thread_impl = AsyncThread + + # NB: there is no public 'create' + get = BaseRuns._get + get_last_by_thread = BaseRuns._get_last_by_thread + list = BaseRuns._list + + +class Runs(BaseRuns[Run, Assistant, Thread]): + _run_impl = Run + _assistant_impl = Assistant + _thread_impl = Thread + + # NB: there is no public 'create' + get = run_sync(BaseRuns._get) + get_last_by_thread = run_sync(BaseRuns._get_last_by_thread) + list = run_sync_generator(BaseRuns._list) diff --git a/src/yandex_cloud_ml_sdk/_runs/result.py b/src/yandex_cloud_ml_sdk/_runs/result.py new file mode 100644 index 0000000..b65f512 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_runs/result.py @@ -0,0 +1,124 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import abc +import dataclasses +from typing import TYPE_CHECKING, Any + +from yandex.cloud.ai.assistants.v1.runs.run_pb2 import Run as ProtoRun +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import StreamEvent as ProtoStreamEvent + +from yandex_cloud_ml_sdk._messages.message import BaseMessage, Message, PartialMessage +from yandex_cloud_ml_sdk._models.completions.result import Usage +from yandex_cloud_ml_sdk._types.result import BaseResult, ProtoResultTypeT + +from .status import BaseRunStatus, RunStatus, StreamEvent + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + + +@dataclasses.dataclass(frozen=True) +class BaseRunResult(BaseRunStatus, BaseResult[ProtoResultTypeT]): + status: BaseRunStatus + error: str | None + _message: BaseMessage | None + + @classmethod + @abc.abstractmethod + def _from_proto(cls, proto: Any, sdk: BaseSDK) -> BaseRunResult: # pylint: disable=arguments-renamed + pass + + @property + def is_running(self) -> bool: + return self.status.is_running + + @property + def is_succeeded(self) -> bool: + return self.status.is_succeeded + + @property + def is_failed(self) -> bool: + return self.status.is_failed + + @property + def message(self) -> BaseMessage: + if self.is_failed: + raise ValueError("run is failed and don't have a message result") + assert self._message + return self._message + + @property + def text(self) -> str: + return self.message.text + + @property + def parts(self) -> tuple[Any]: + return self.message.parts + + +@dataclasses.dataclass(frozen=True) +class RunResult(BaseRunResult[ProtoRun]): + _proto_result_type = ProtoRun + + _message: Message | None + status: RunStatus + usage: Usage | None + + @classmethod + def _from_proto(cls, proto: ProtoRun, sdk: BaseSDK) -> RunResult: + usage: Usage | None = None + + if proto.HasField('usage'): + usage = Usage( + completion_tokens=proto.usage.completion_tokens, + input_text_tokens=proto.usage.prompt_tokens, + total_tokens=proto.usage.total_tokens + ) + + state = proto.state + + error: str | None = None + if state.HasField('error'): + error = state.error.message + + completed_message: Message | None = None + if state.HasField('completed_message'): + completed_message = Message._from_proto( + sdk=sdk, + proto=state.completed_message + ) + + # pylint: disable=unexpected-keyword-arg + return cls( + status=RunStatus._from_proto(proto.state.status), + error=error, + _message=completed_message, + usage=usage, + ) + + +@dataclasses.dataclass(frozen=True) +class RunStreamEvent(BaseRunResult[ProtoStreamEvent]): + _proto_result_type = ProtoStreamEvent + status: StreamEvent + + @classmethod + def _from_proto(cls, proto: ProtoStreamEvent, sdk: BaseSDK) -> RunStreamEvent: + message: BaseMessage | None = None + if proto.HasField('partial_message'): + message = PartialMessage._from_proto(sdk=sdk, proto=proto.partial_message) + elif proto.HasField('completed_message'): + message = Message._from_proto(sdk=sdk, proto=proto.completed_message) + + error: str | None = None + if proto.HasField('error'): + error = proto.error.message + + # pylint: disable=unexpected-keyword-arg + return cls( + status=StreamEvent._from_proto(proto.event_type), + error=error, + _message=message, + ) diff --git a/src/yandex_cloud_ml_sdk/_runs/run.py b/src/yandex_cloud_ml_sdk/_runs/run.py new file mode 100644 index 0000000..5b08ff5 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_runs/run.py @@ -0,0 +1,117 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +from datetime import datetime +from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar + +from google.protobuf.wrappers_pb2 import Int64Value +from yandex.cloud.ai.assistants.v1.runs.run_pb2 import Run as ProtoRun +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import GetRunRequest, ListenRunRequest +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import StreamEvent as ProtoStreamEvent +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2_grpc import RunServiceStub + +from yandex_cloud_ml_sdk._types.operation import OperationInterface +from yandex_cloud_ml_sdk._types.resource import BaseResource +from yandex_cloud_ml_sdk._utils.proto import get_google_value +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .result import RunResult, RunStreamEvent +from .status import RunStatus + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +@dataclasses.dataclass(frozen=True) +class BaseRun(BaseResource, OperationInterface[RunResult]): + id: str + assistant_id: str + thread_id: str + created_by: str + created_at: datetime + labels: dict[str, str] | None + custom_temperature: float | None + custom_max_tokens: int | None + custom_max_prompt_tokens: int | None + + @classmethod + def _kwargs_from_message(cls, proto: ProtoRun, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) + + kwargs.update({ + 'custom_temperature': get_google_value(proto.custom_completion_options, 'temperature', None, float), + 'custom_max_tokens': get_google_value(proto.custom_completion_options, 'max_tokens', None, int), + 'custom_max_prompt_tokens': get_google_value( + proto.custom_prompt_truncation_options, 'max_prompt_tokens', None, int + ), + }) + + return kwargs + + async def _get_run(self, *, timeout=60) -> ProtoRun: + request = GetRunRequest(run_id=self.id) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoRun, + ) + + return response + + async def _get_status(self, *, timeout=60) -> RunStatus: # type: ignore[override] + run = await self._get_run(timeout=timeout) + + return RunStatus._from_proto(proto=run.state.status) + + async def _get_result(self, *, timeout=60) -> RunResult: + run = await self._get_run(timeout=timeout) + + return RunResult._from_proto(sdk=self._sdk, proto=run) + + async def _listen( + self, + *, + events_start_idx: int = 0, + timeout=60, + ) -> AsyncIterator[RunStreamEvent]: + request = ListenRunRequest( + run_id=self.id, + events_start_idx=Int64Value(value=events_start_idx), + ) + + async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: + async for response in self._client.call_service_stream( + stub.Listen, + request, + timeout=timeout, + expected_type=ProtoStreamEvent, + ): + yield RunStreamEvent._from_proto(response, sdk=self._sdk) + + return + + +class AsyncRun(BaseRun): + get_status = BaseRun._get_status + get_result = BaseRun._get_result + wait = BaseRun._wait + listen = BaseRun._listen + __aiter__ = BaseRun._listen + + def __await__(self): + return self.wait().__await__() + + +class Run(BaseRun): + get_status = run_sync(BaseRun._get_status) + get_result = run_sync(BaseRun._get_result) + wait = run_sync(BaseRun._wait) + listen = run_sync_generator(BaseRun._listen) + __iter__ = run_sync_generator(BaseRun._listen) + + +RunTypeT = TypeVar('RunTypeT', bound=BaseRun) diff --git a/src/yandex_cloud_ml_sdk/_runs/status.py b/src/yandex_cloud_ml_sdk/_runs/status.py new file mode 100644 index 0000000..def4bbe --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_runs/status.py @@ -0,0 +1,76 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import enum + +from yandex.cloud.ai.assistants.v1.runs.run_pb2 import RunState as ProtoRunState +from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import StreamEvent as ProtoStreamEvent + + +class BaseRunStatus: + @property + def is_running(self) -> bool: + raise NotImplementedError() + + @property + def is_succeeded(self) -> bool: + raise NotImplementedError() + + @property + def is_failed(self) -> bool: + raise NotImplementedError() + + +class RunStatus(BaseRunStatus, int, enum.Enum): + UNKNOWN = -1 + RUN_STATUS_UNSPECIFIED = ProtoRunState.RUN_STATUS_UNSPECIFIED + PENDING = ProtoRunState.PENDING + IN_PROGRESS = ProtoRunState.IN_PROGRESS + FAILED = ProtoRunState.FAILED + COMPLETED = ProtoRunState.COMPLETED + + @property + def is_running(self) -> bool: + return self in (self.IN_PROGRESS, self.PENDING) + + @property + def is_succeeded(self) -> bool: + return self is self.COMPLETED + + @property + def is_failed(self) -> bool: + return self is self.FAILED + + @classmethod + def _from_proto(cls, proto: int) -> RunStatus: + try: + return cls(proto) + except ValueError: + return cls(-1) + + +class StreamEvent(BaseRunStatus, int, enum.Enum): + UNKNOWN = -1 + EVENT_TYPE_UNSPECIFIED = ProtoStreamEvent.EVENT_TYPE_UNSPECIFIED + PARTIAL_MESSAGE = ProtoStreamEvent.PARTIAL_MESSAGE + ERROR = ProtoStreamEvent.ERROR + DONE = ProtoStreamEvent.DONE + + @property + def is_running(self) -> bool: + return self is self.PARTIAL_MESSAGE + + @property + def is_succeeded(self) -> bool: + return self is self.DONE + + @property + def is_failed(self) -> bool: + return self is self.ERROR + + @classmethod + def _from_proto(cls, proto: int) -> StreamEvent: + try: + return cls(proto) + except ValueError: + return cls(-1) diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 278cb24..b64a076 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -9,14 +9,15 @@ from get_annotations import get_annotations from grpc import aio -from ._assistants.domain import Assistants, AsyncAssistants +from ._assistants.domain import Assistants, AsyncAssistants, BaseAssistants from ._auth import BaseAuth from ._client import AsyncCloudClient -from ._files.domain import AsyncFiles, Files +from ._files.domain import AsyncFiles, BaseFiles, Files from ._messages.domain import AsyncMessages, BaseMessages, Messages from ._models import AsyncModels, BaseModels, Models from ._retry import RetryPolicy -from ._threads.domain import AsyncThreads, Threads +from ._runs.domain import AsyncRuns, BaseRuns, Runs +from ._threads.domain import AsyncThreads, BaseThreads, Threads from ._types.domain import BaseDomain from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined @@ -24,6 +25,10 @@ class BaseSDK: _messages: BaseMessages models: BaseModels + threads: BaseThreads + files: BaseFiles + assistants: BaseAssistants + runs: BaseRuns def __init__( self, @@ -137,6 +142,7 @@ class AsyncYCloudML(BaseSDK): files: AsyncFiles threads: AsyncThreads assistants: AsyncAssistants + runs: AsyncRuns _messages: AsyncMessages @@ -145,4 +151,5 @@ class YCloudML(BaseSDK): files: Files threads: Threads assistants: Assistants + runs: Runs _messages: Messages diff --git a/src/yandex_cloud_ml_sdk/_threads/domain.py b/src/yandex_cloud_ml_sdk/_threads/domain.py index 84a1a4d..75558e3 100644 --- a/src/yandex_cloud_ml_sdk/_threads/domain.py +++ b/src/yandex_cloud_ml_sdk/_threads/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic, TypeVar +from typing import AsyncIterator, Generic from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2 import ( @@ -14,9 +14,7 @@ from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator -from .thread import AsyncThread, BaseThread, Thread - -ThreadTypeT = TypeVar('ThreadTypeT', bound=BaseThread) +from .thread import AsyncThread, Thread, ThreadTypeT class BaseThreads(BaseDomain, Generic[ThreadTypeT]): diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py index 8b2115c..965325b 100644 --- a/src/yandex_cloud_ml_sdk/_threads/thread.py +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any, AsyncIterator +from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar from typing_extensions import Self from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread @@ -162,3 +162,6 @@ class Thread(RichThread): write = run_sync(RichThread._write) read = run_sync_generator(RichThread._read) __iter__ = run_sync_generator(RichThread._read) + + +ThreadTypeT = TypeVar('ThreadTypeT', bound=BaseThread) diff --git a/src/yandex_cloud_ml_sdk/_types/operation.py b/src/yandex_cloud_ml_sdk/_types/operation.py index 55ac765..ec91cd5 100644 --- a/src/yandex_cloud_ml_sdk/_types/operation.py +++ b/src/yandex_cloud_ml_sdk/_types/operation.py @@ -44,7 +44,42 @@ def is_failed(self) -> bool: return bool(self.done and self.error and self.error.code > 0) -class BaseOperation(abc.ABC, Generic[ResultTypeT]): +class OperationInterface(abc.ABC, Generic[ResultTypeT]): + id: str + + @abc.abstractmethod + async def _get_status(self, *, timeout=60) -> OperationStatus: + pass + + @abc.abstractmethod + async def _get_result(self, *, timeout=60) -> ResultTypeT: + pass + + async def _wait_impl(self, timeout, poll_interval) -> OperationStatus: + status = await self._get_status(timeout=timeout) + while status.is_running: + await asyncio.sleep(poll_interval) + status = await self._get_status(timeout=timeout) + + return status + + async def _wait( + self, + *, + timeout: int = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> ResultTypeT: + coro = self._wait_impl(timeout=timeout, poll_interval=poll_interval) + if poll_timeout: + coro = asyncio.wait_for(coro, timeout=poll_timeout) + + await coro + + return await self._get_result(timeout=timeout) + + +class BaseOperation(OperationInterface[ResultTypeT]): _last_known_status: OperationStatus | None def __init__(self, sdk: BaseSDK, id: str, result_type: type[ResultTypeT]): # pylint: disable=redefined-builtin @@ -89,7 +124,7 @@ async def _get_result(self, *, timeout=60) -> ResultTypeT: # NB: mypy can't figure out that self._result_type._from_proto is # returning instance of self._result_type which is also is a ResultTypeT - return cast(ResultTypeT, self._result_type._from_proto(proto_result)) + return cast(ResultTypeT, self._result_type._from_proto(proto_result, sdk=self._sdk)) if status.is_failed: assert status.error is not None @@ -104,29 +139,6 @@ async def _get_result(self, *, timeout=60) -> ResultTypeT: f"operation {self.id} is done but response have result neither error fields set" ) - async def _wait_impl(self, timeout, poll_interval) -> OperationStatus: - status = await self._get_status(timeout=timeout) - while status.is_running: - await asyncio.sleep(poll_interval) - status = await self._get_status(timeout=timeout) - - return status - - async def _wait( - self, - *, - timeout: int = 60, - poll_timeout: int = 3600, - poll_interval: float = 10, - ) -> ResultTypeT: - coro = self._wait_impl(timeout=timeout, poll_interval=poll_interval) - if poll_timeout: - coro = asyncio.wait_for(coro, timeout=poll_timeout) - - await coro - - return await self._get_result(timeout=timeout) - async def _cancel(self, *, timeout=60) -> OperationStatus: request = CancelOperationRequest(operation_id=self.id) async with self._client.get_service_stub(OperationServiceStub, timeout=timeout) as stub: diff --git a/src/yandex_cloud_ml_sdk/_types/result.py b/src/yandex_cloud_ml_sdk/_types/result.py index ab0df95..a34c2d7 100644 --- a/src/yandex_cloud_ml_sdk/_types/result.py +++ b/src/yandex_cloud_ml_sdk/_types/result.py @@ -1,11 +1,14 @@ from __future__ import annotations import abc -from typing import Generic, TypeVar +from typing import TYPE_CHECKING, Generic, TypeVar from google.protobuf.message import Message from typing_extensions import Self +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + ProtoResultTypeT = TypeVar('ProtoResultTypeT', bound=Message) T = TypeVar('T', bound='BaseResult') @@ -15,5 +18,5 @@ class BaseResult(abc.ABC, Generic[ProtoResultTypeT]): @classmethod @abc.abstractmethod - def _from_proto(cls: type[Self], message: ProtoResultTypeT) -> Self: + def _from_proto(cls: type[Self], message: ProtoResultTypeT, sdk: BaseSDK) -> Self: raise NotImplementedError() diff --git a/src/yandex_cloud_ml_sdk/_utils/proto.py b/src/yandex_cloud_ml_sdk/_utils/proto.py index b8a2882..4e84a98 100644 --- a/src/yandex_cloud_ml_sdk/_utils/proto.py +++ b/src/yandex_cloud_ml_sdk/_utils/proto.py @@ -1,11 +1,14 @@ from __future__ import annotations -from typing import Any +from typing import Any, TypeVar, cast from google.protobuf.json_format import MessageToDict from google.protobuf.message import Message from google.protobuf.timestamp_pb2 import Timestamp # pylint: disable=no-name-in-module +_T = TypeVar('_T') +_D = TypeVar('_D') + def proto_to_dict(message: Message) -> dict[str, Any]: dct = MessageToDict( @@ -17,3 +20,15 @@ def proto_to_dict(message: Message) -> dict[str, Any]: if isinstance(value, Timestamp): dct[descriptor.name] = value.ToDatetime() return dct + + +def get_google_value( + message: Message, + field_name: str, + default: _D, + expected_type: type[_T], # pylint: disable=unused-argument +) -> _T | _D: + if message.HasField(field_name): + return cast(_T, getattr(message, field_name).value) + + return cast(_D, default) diff --git a/tests/assistants/cassettes/test_run/test_run.gprc.json b/tests/assistants/cassettes/test_run/test_run.gprc.json new file mode 100644 index 0000000..1cc953a --- /dev/null +++ b/tests/assistants/cassettes/test_run/test_run.gprc.json @@ -0,0 +1,734 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtma67v8qu3u0gfk39j", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.366713Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T17:50:32.366713Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T17:50:32.366713Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvtpf3d15g8sre5hufrq", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt8e94n940u5vqrmlff", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.549834Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T17:50:32.549834Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T17:50:32.549834Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvtpf3d15g8sre5hufrq", + "content": { + "content": [ + { + "text": { + "content": "hey!" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtcbsr8c86kov6s3g13", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.678556Z", + "author": { + "id": "fvt8e94n940u5vqrmlff", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "hey!" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "assistantId": "fvtma67v8qu3u0gfk39j", + "threadId": "fvtpf3d15g8sre5hufrq", + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtebr1iaqjrhv8pm4d7", + "assistantId": "fvtma67v8qu3u0gfk39j", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.786256525Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtebr1iaqjrhv8pm4d7" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtebr1iaqjrhv8pm4d7", + "assistantId": "fvtma67v8qu3u0gfk39j", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.786256525Z", + "state": { + "status": "IN_PROGRESS" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtebr1iaqjrhv8pm4d7" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtebr1iaqjrhv8pm4d7", + "assistantId": "fvtma67v8qu3u0gfk39j", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.786256525Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvteciohdf933ubp6eei", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:33.468666415Z", + "author": { + "id": "fvtma67v8qu3u0gfk39j", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "12", + "completionTokens": "7", + "totalTokens": "19" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtebr1iaqjrhv8pm4d7" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtebr1iaqjrhv8pm4d7", + "assistantId": "fvtma67v8qu3u0gfk39j", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:32.786256525Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvteciohdf933ubp6eei", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:33.468666415Z", + "author": { + "id": "fvtma67v8qu3u0gfk39j", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "12", + "completionTokens": "7", + "totalTokens": "19" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "ListenRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtebr1iaqjrhv8pm4d7", + "eventsStartIdx": "0" + } + }, + "response_stream": [ + { + "cls": "StreamEvent", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "eventType": "PARTIAL_MESSAGE", + "streamCursor": {}, + "partialMessage": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + { + "cls": "StreamEvent", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "eventType": "DONE", + "streamCursor": { + "currentEventIdx": "1" + }, + "completedMessage": { + "id": "fvteciohdf933ubp6eei", + "threadId": "fvtpf3d15g8sre5hufrq", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:50:33.468666415Z", + "author": { + "id": "fvtma67v8qu3u0gfk39j", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + } + } + ] + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtma67v8qu3u0gfk39j" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvtpf3d15g8sre5hufrq" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_run/test_run_methods.gprc.json b/tests/assistants/cassettes/test_run/test_run_methods.gprc.json new file mode 100644 index 0000000..3934cb9 --- /dev/null +++ b/tests/assistants/cassettes/test_run/test_run_methods.gprc.json @@ -0,0 +1,934 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt2pd46knif6bodrp2l", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:28.907883Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T18:04:28.907883Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T18:04:28.907883Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvta4t7h0lge8e9inqmn", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtb5djg1suv54v69hhl", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.082776Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T18:04:29.082776Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T18:04:29.082776Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvta4t7h0lge8e9inqmn", + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtbub69hj447aekanuu", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.288123Z", + "author": { + "id": "fvtb5djg1suv54v69hhl", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "foo" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt545gslp1l24t5b36m", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtfugvgh1uhf3vcvnup", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.565526Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T18:04:29.565526Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T18:04:29.565526Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvta4t7h0lge8e9inqmn", + "content": { + "content": [ + { + "text": { + "content": "bar" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtc21pv3jsf3sbidbg9", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.714100Z", + "author": { + "id": "fvtb5djg1suv54v69hhl", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "bar" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvt7pc15hb1aqrs9v7u4", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.849745973Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvt7pc15hb1aqrs9v7u4" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvt7pc15hb1aqrs9v7u4", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.849745973Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvt7pc15hb1aqrs9v7u4" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvt7pc15hb1aqrs9v7u4", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.849745973Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvt9jb40befje9op5340", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:30.776293463Z", + "author": { + "id": "fvt2pd46knif6bodrp2l", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "foo\nbar" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "13", + "completionTokens": "4", + "totalTokens": "17" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvt7pc15hb1aqrs9v7u4" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvt7pc15hb1aqrs9v7u4", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.849745973Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvt9jb40befje9op5340", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:30.776293463Z", + "author": { + "id": "fvt2pd46knif6bodrp2l", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "foo\nbar" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "13", + "completionTokens": "4", + "totalTokens": "17" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtmhjdsak0g0en8a17m", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:40.187863142Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtmhjdsak0g0en8a17m" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtmhjdsak0g0en8a17m", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:40.187863142Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtmhjdsak0g0en8a17m" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtmhjdsak0g0en8a17m", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:40.187863142Z", + "state": { + "status": "FAILED", + "error": { + "message": "thread has no messages" + } + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtmhjdsak0g0en8a17m" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtmhjdsak0g0en8a17m", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:40.187863142Z", + "state": { + "status": "FAILED", + "error": { + "message": "thread has no messages" + } + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvt7pc15hb1aqrs9v7u4" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvt7pc15hb1aqrs9v7u4", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:29.849745973Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvt9jb40befje9op5340", + "threadId": "fvta4t7h0lge8e9inqmn", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:30.776293463Z", + "author": { + "id": "fvt2pd46knif6bodrp2l", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "foo\nbar" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "13", + "completionTokens": "4", + "totalTokens": "17" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetLastRunByThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "threadId": "fvt545gslp1l24t5b36m" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtmhjdsak0g0en8a17m", + "assistantId": "fvt2pd46knif6bodrp2l", + "threadId": "fvt545gslp1l24t5b36m", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T18:04:40.187863142Z", + "state": { + "status": "FAILED", + "error": { + "message": "thread has no messages" + } + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt2pd46knif6bodrp2l" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvta4t7h0lge8e9inqmn" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt545gslp1l24t5b36m" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_run/test_run_stream.gprc.json b/tests/assistants/cassettes/test_run/test_run_stream.gprc.json new file mode 100644 index 0000000..69d0c5d --- /dev/null +++ b/tests/assistants/cassettes/test_run/test_run_stream.gprc.json @@ -0,0 +1,754 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvtdhek1qnro3d12e4j1", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.057957Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T17:51:00.057957Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T17:51:00.057957Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {} + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt1t9n0g32cl3v867cj", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvt3od27ir5b0bab3ce1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.229522Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-24T17:51:00.229522Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-10-31T17:51:00.229522Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt1t9n0g32cl3v867cj", + "content": { + "content": [ + { + "text": { + "content": "hey!" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvt20janeqk35ue2htqj", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.386867Z", + "author": { + "id": "fvt3od27ir5b0bab3ce1", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "hey!" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "assistantId": "fvtdhek1qnro3d12e4j1", + "threadId": "fvt1t9n0g32cl3v867cj", + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + }, + "stream": true + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtgvl288vhh41s4nbc6", + "assistantId": "fvtdhek1qnro3d12e4j1", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.518831167Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtgvl288vhh41s4nbc6" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtgvl288vhh41s4nbc6", + "assistantId": "fvtdhek1qnro3d12e4j1", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.518831167Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtgvl288vhh41s4nbc6" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtgvl288vhh41s4nbc6", + "assistantId": "fvtdhek1qnro3d12e4j1", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.518831167Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvta8p3pkmgvjkea4iv4", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:01.813068045Z", + "author": { + "id": "fvtdhek1qnro3d12e4j1", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "12", + "completionTokens": "7", + "totalTokens": "19" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtgvl288vhh41s4nbc6" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvtgvl288vhh41s4nbc6", + "assistantId": "fvtdhek1qnro3d12e4j1", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:00.518831167Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvta8p3pkmgvjkea4iv4", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:01.813068045Z", + "author": { + "id": "fvtdhek1qnro3d12e4j1", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "12", + "completionTokens": "7", + "totalTokens": "19" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": { + "temperature": 0.0 + } + } + } + }, + { + "request": { + "cls": "ListenRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvtgvl288vhh41s4nbc6", + "eventsStartIdx": "0" + } + }, + "response_stream": [ + { + "cls": "StreamEvent", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "eventType": "PARTIAL_MESSAGE", + "streamCursor": {}, + "partialMessage": { + "content": [ + { + "text": { + "content": "Hello" + } + } + ] + } + } + }, + { + "cls": "StreamEvent", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "eventType": "PARTIAL_MESSAGE", + "streamCursor": { + "currentEventIdx": "1" + }, + "partialMessage": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + }, + { + "cls": "StreamEvent", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "eventType": "DONE", + "streamCursor": { + "currentEventIdx": "2" + }, + "completedMessage": { + "id": "fvta8p3pkmgvjkea4iv4", + "threadId": "fvt1t9n0g32cl3v867cj", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-24T17:51:01.813068045Z", + "author": { + "id": "fvtdhek1qnro3d12e4j1", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "Hello! How are you?" + } + } + ] + } + } + } + } + ] + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvtdhek1qnro3d12e4j1" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt1t9n0g32cl3v867cj" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_assistants.py b/tests/assistants/test_assistants.py index af5f1b4..74a91c3 100644 --- a/tests/assistants/test_assistants.py +++ b/tests/assistants/test_assistants.py @@ -104,7 +104,7 @@ async def test_assistant_deleted(async_sdk): await getattr(assistant, method)() with pytest.raises(ValueError): - await assistant.delete('foo') + await assistant.delete() @pytest.mark.allow_grpc diff --git a/tests/assistants/test_messages.py b/tests/assistants/test_messages.py index 9892728..da30a72 100644 --- a/tests/assistants/test_messages.py +++ b/tests/assistants/test_messages.py @@ -17,7 +17,7 @@ async def test_message(async_sdk): labels={'foo': 'bar'}, ) - assert message.parts == ['foo'] + assert message.parts == ('foo', ) assert message.labels == {'foo': 'bar'} assert message.thread_id == thread.id assert message.text == 'foo' diff --git a/tests/assistants/test_run.py b/tests/assistants/test_run.py new file mode 100644 index 0000000..60c43db --- /dev/null +++ b/tests/assistants/test_run.py @@ -0,0 +1,97 @@ +# pylint: disable=protected-access +from __future__ import annotations + +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_run(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + thread = await async_sdk.threads.create() + await thread.write('hey!') + run = await assistant.run(thread, custom_temperature=0) + result = await run + + assert result.is_succeeded + assert result.status.name == 'COMPLETED' + assert result.text == 'Hello! How are you?' + assert result.parts == ('Hello! How are you?', ) + assert result.error is None + assert result.usage.completion_tokens > 0 + + events = [e async for e in run] + assert len(events) == 2 + assert events[1].text == result.text + + await assistant.delete() + await thread.delete() + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_run_stream(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + thread = await async_sdk.threads.create() + await thread.write('hey!') + run = await assistant.run_stream(thread, custom_temperature=0) + result = await run + + assert result.is_succeeded + assert result.status.name == 'COMPLETED' + assert result.text == 'Hello! How are you?' + assert result.parts == ('Hello! How are you?', ) + assert result.error is None + assert result.usage.completion_tokens > 0 + + events = [e async for e in run] + assert len(events) == 3 + partial1, partial2, completed = events + + assert partial1.status.name == 'PARTIAL_MESSAGE' + assert partial1.text == 'Hello' + assert partial1.error is None + + assert partial2.text == result.text + assert partial2.status.name == 'PARTIAL_MESSAGE' + assert partial2.error is None + + assert completed.status.name == 'DONE' + assert completed.text == result.text + assert completed.error is None + + await assistant.delete() + await thread.delete() + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_run_methods(async_sdk): + assistant = await async_sdk.assistants.create('yandexgpt') + thread1 = await async_sdk.threads.create() + await thread1.write('foo') + thread2 = await async_sdk.threads.create() + await thread1.write('bar') + + run1 = await assistant.run(thread1) + await run1 + run2 = await assistant.run(thread2) + await run2 + + run11 = await async_sdk.runs.get(run1.id) + assert run1 == run11 + + run22 = await async_sdk.runs.get_last_by_thread(thread2) + assert run2 == run22 + + # it doesn't work at the moment at the backend + # all_runs = [r async for r in async_sdk.runs.list()] + # all_runs_ids = [r.id for r in all_runs] + # assert run1.id in all_runs_ids + # assert run2.id in all_runs_ids + + await assistant.delete() + await thread1.delete() + await thread2.delete() From 2421c6d5ac45662b330be37d99161e76c7285ad5 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Wed, 30 Oct 2024 18:45:23 +0100 Subject: [PATCH 07/13] Assistants search indexes (#9) --- .../async/assistants/maldives_example.txt | 1 + examples/async/assistants/runs.py | 4 +- examples/async/assistants/search_indexes.py | 63 + examples/async/assistants/search_query.txt | 3 + examples/async/assistants/turkey_example.txt | 170 ++ pyproject.toml | 2 + .../_assistants/assistant.py | 8 +- src/yandex_cloud_ml_sdk/_files/domain.py | 6 +- src/yandex_cloud_ml_sdk/_files/file.py | 23 +- src/yandex_cloud_ml_sdk/_files/utils.py | 20 + .../_models/completions/model.py | 6 +- .../_models/completions/result.py | 12 +- .../_models/text_classifiers/result.py | 6 +- .../_models/text_embeddings/result.py | 8 +- src/yandex_cloud_ml_sdk/_sdk.py | 7 +- .../_search_indexes/__init__.py | 0 .../_search_indexes/chunking_strategy.py | 56 + .../_search_indexes/domain.py | 151 ++ .../_search_indexes/file.py | 36 + .../_search_indexes/index_type.py | 90 + .../_search_indexes/search_index.py | 194 ++ src/yandex_cloud_ml_sdk/_threads/thread.py | 20 +- src/yandex_cloud_ml_sdk/_types/expiration.py | 10 +- src/yandex_cloud_ml_sdk/_types/model.py | 3 +- src/yandex_cloud_ml_sdk/_types/operation.py | 25 +- src/yandex_cloud_ml_sdk/_types/resource.py | 15 + src/yandex_cloud_ml_sdk/_types/result.py | 2 +- src/yandex_cloud_ml_sdk/search_indexes.py | 10 + .../test_search_index.gprc.json | 770 ++++++ .../test_search_index_deleted.gprc.json | 529 ++++ .../test_search_index_list.gprc.json | 2140 +++++++++++++++++ tests/assistants/test_search_indexes.py | 95 + tests/conftest.py | 3 +- 33 files changed, 4417 insertions(+), 71 deletions(-) create mode 100644 examples/async/assistants/maldives_example.txt create mode 100755 examples/async/assistants/search_indexes.py create mode 100644 examples/async/assistants/search_query.txt create mode 100644 examples/async/assistants/turkey_example.txt create mode 100644 src/yandex_cloud_ml_sdk/_files/utils.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/chunking_strategy.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/file.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/index_type.py create mode 100644 src/yandex_cloud_ml_sdk/_search_indexes/search_index.py create mode 100644 src/yandex_cloud_ml_sdk/search_indexes.py create mode 100644 tests/assistants/cassettes/test_search_indexes/test_search_index.gprc.json create mode 100644 tests/assistants/cassettes/test_search_indexes/test_search_index_deleted.gprc.json create mode 100644 tests/assistants/cassettes/test_search_indexes/test_search_index_list.gprc.json create mode 100644 tests/assistants/test_search_indexes.py diff --git a/examples/async/assistants/maldives_example.txt b/examples/async/assistants/maldives_example.txt new file mode 100644 index 0000000..71029a7 --- /dev/null +++ b/examples/async/assistants/maldives_example.txt @@ -0,0 +1 @@ +Стоимость въезда/выезда с Мальдив - 10 тысяч долларов в обе стороны diff --git a/examples/async/assistants/runs.py b/examples/async/assistants/runs.py index d31c17f..6dabffb 100755 --- a/examples/async/assistants/runs.py +++ b/examples/async/assistants/runs.py @@ -44,8 +44,8 @@ async def main() -> None: run = await sdk.runs.get_last_by_thread(thread) print('last run:', run) - async for run in sdk.runs.list(page_size=10): - print('run:', run) + # async for run in sdk.runs.list(page_size=10): + # print('run:', run) async for assistant in sdk.assistants.list(): await assistant.delete() diff --git a/examples/async/assistants/search_indexes.py b/examples/async/assistants/search_indexes.py new file mode 100755 index 0000000..8cd54cd --- /dev/null +++ b/examples/async/assistants/search_indexes.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio +import pathlib + +from yandex_cloud_ml_sdk import AsyncYCloudML +from yandex_cloud_ml_sdk.search_indexes import StaticIndexChunkingStrategy, TextSearchIndexType + + +def local_path(path: str) -> pathlib.Path: + return pathlib.Path(__file__).parent / path + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-files': 'assistant.api.cloud.yandex.net', + 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'operation': 'assistant.api.cloud.yandex.net', + } + ) + + file_coros = ( + sdk.files.upload( + local_path(path), + ttl_days=5, + expiration_policy="static", + ) + for path in ['turkey_example.txt', 'maldives_example.txt'] + ) + files = await asyncio.gather(*file_coros) + + operation = await sdk.search_indexes.create_deferred( + files, + index_type=TextSearchIndexType( + chunking_strategy=StaticIndexChunkingStrategy( + max_chunk_size_tokens=700, + chunk_overlap_tokens=300, + ) + ) + ) + search_index = await operation.wait() + print(f"search index {search_index}") + + index_files = [file async for file in search_index.list_files()] + print(f"search index files: {index_files}") + index_file = await search_index.get_file(index_files[0].id) + print(f"search index file: {index_file}") + + for file in files: + print(f"delete file {file}") + await file.delete() + + async for search_index in sdk.search_indexes.list(): + print(f"delete search_index {search_index}") + await search_index.delete() + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/assistants/search_query.txt b/examples/async/assistants/search_query.txt new file mode 100644 index 0000000..feea401 --- /dev/null +++ b/examples/async/assistants/search_query.txt @@ -0,0 +1,3 @@ +Какова стоимость выездной пошлины для путешествия в чарующие и солнечные МАЛЬДИВЫ, +где беззаботный отдых на восхитительных пляжах, утопающих в лучах мягкого средиземноморского солнца, +соединяется с открытием величественных исторических памятников и наслаждением изысканными ароматами местной кухни? diff --git a/examples/async/assistants/turkey_example.txt b/examples/async/assistants/turkey_example.txt new file mode 100644 index 0000000..8ff4a7a --- /dev/null +++ b/examples/async/assistants/turkey_example.txt @@ -0,0 +1,170 @@ +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ diff --git a/pyproject.toml b/pyproject.toml index 4bb6ea2..da61938 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -227,6 +227,8 @@ exclude-protected= [ "_sdk", "_folder_id", "_from_proto", + "_from_upper_proto", + "_to_proto", "_result_type", "_proto_result_type", ] diff --git a/src/yandex_cloud_ml_sdk/_assistants/assistant.py b/src/yandex_cloud_ml_sdk/_assistants/assistant.py index e0b5434..06234bf 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/assistant.py +++ b/src/yandex_cloud_ml_sdk/_assistants/assistant.py @@ -18,7 +18,7 @@ from yandex_cloud_ml_sdk._threads.thread import AsyncThread, Thread, ThreadTypeT from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined -from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete +from yandex_cloud_ml_sdk._types.resource import ExpirableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync_generator_impl, run_sync_impl from .utils import get_completion_options, get_prompt_trunctation_options @@ -28,7 +28,7 @@ @dataclasses.dataclass(frozen=True) -class BaseAssistant(BaseDeleteableResource, Generic[RunTypeT, ThreadTypeT]): +class BaseAssistant(ExpirableResource, Generic[RunTypeT, ThreadTypeT]): expiration_config: ExpirationConfig model: BaseGPTModel instruction: str | None @@ -48,10 +48,6 @@ def _kwargs_from_message(cls, proto: ProtoAssistant, sdk: BaseSDK) -> dict[str, if max_prompt_tokens := proto.prompt_truncation_options.max_prompt_tokens.value: kwargs['max_prompt_tokens'] = max_prompt_tokens - kwargs['expiration_config'] = ExpirationConfig.coerce( - ttl_days=proto.expiration_config.ttl_days, - expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] - ) return kwargs # pylint: disable=too-many-arguments diff --git a/src/yandex_cloud_ml_sdk/_files/domain.py b/src/yandex_cloud_ml_sdk/_files/domain.py index 63bbf94..46c8b28 100644 --- a/src/yandex_cloud_ml_sdk/_files/domain.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic, TypeVar +from typing import AsyncIterator, Generic from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile from yandex.cloud.ai.files.v1.file_service_pb2 import ( @@ -14,9 +14,7 @@ from yandex_cloud_ml_sdk._types.misc import UNDEFINED, PathLike, UndefinedOr, coerce_path, get_defined_value, is_defined from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator -from .file import AsyncFile, BaseFile, File - -FileTypeT = TypeVar('FileTypeT', bound=BaseFile) +from .file import AsyncFile, File, FileTypeT class BaseFiles(BaseDomain, Generic[FileTypeT]): diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py index d94ef95..d8041dc 100644 --- a/src/yandex_cloud_ml_sdk/_files/file.py +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any +from typing import TypeVar import httpx from typing_extensions import Self @@ -15,26 +15,12 @@ from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value -from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete +from yandex_cloud_ml_sdk._types.resource import ExpirableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync -if TYPE_CHECKING: - from yandex_cloud_ml_sdk._sdk import BaseSDK - @dataclasses.dataclass(frozen=True) -class BaseFile(BaseDeleteableResource): - expiration_config: ExpirationConfig - - @classmethod - def _kwargs_from_message(cls, proto: ProtoFile, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] - kwargs = super()._kwargs_from_message(proto, sdk=sdk) - kwargs['expiration_config'] = ExpirationConfig.coerce( - ttl_days=proto.expiration_config.ttl_days, - expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] - ) - return kwargs - +class BaseFile(ExpirableResource): @safe_on_delete async def _get_url( self, @@ -166,3 +152,6 @@ class File(RichFile): update = run_sync(RichFile._update) delete = run_sync(RichFile._delete) download_as_bytes = run_sync(RichFile._download_as_bytes) + + +FileTypeT = TypeVar('FileTypeT', bound=BaseFile) diff --git a/src/yandex_cloud_ml_sdk/_files/utils.py b/src/yandex_cloud_ml_sdk/_files/utils.py new file mode 100644 index 0000000..6eeea94 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_files/utils.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +from typing import Iterable, Union + +from .file import BaseFile + +FileType = Union[str, BaseFile, Iterable[BaseFile], Iterable[str]] + + +def coerce_file_ids(files: FileType) -> tuple[str, ...]: + if isinstance(files, str): + return (files, ) + + if isinstance(files, BaseFile): + return (files.id, ) + + return tuple( + file.id if isinstance(file, BaseFile) else file + for file in files + ) diff --git a/src/yandex_cloud_ml_sdk/_models/completions/model.py b/src/yandex_cloud_ml_sdk/_models/completions/model.py index eab2896..8e1c144 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/model.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/model.py @@ -1,4 +1,4 @@ -# pylint: disable=arguments-renamed,no-name-in-module +# pylint: disable=arguments-renamed,no-name-in-module,protected-access from __future__ import annotations from typing import TYPE_CHECKING, Any, AsyncIterator, Iterable, Literal @@ -176,7 +176,7 @@ async def _tokenize( return tuple(Token._from_proto(t) for t in response.tokens) -class AsyncGPTModel(BaseGPTModel): +class AsyncGPTModel(BaseGPTModel[AsyncOperation[GPTModelResult]]): run = BaseGPTModel._run run_stream = BaseGPTModel._run_stream run_deferred = BaseGPTModel._run_deferred @@ -184,7 +184,7 @@ class AsyncGPTModel(BaseGPTModel): _operation_type = AsyncOperation -class GPTModel(BaseGPTModel): +class GPTModel(BaseGPTModel[Operation[GPTModelResult]]): run = run_sync(BaseGPTModel._run) run_stream = run_sync_generator(BaseGPTModel._run_stream) run_deferred = run_sync(BaseGPTModel._run_deferred) diff --git a/src/yandex_cloud_ml_sdk/_models/completions/result.py b/src/yandex_cloud_ml_sdk/_models/completions/result.py index 3ffa2d4..7d817da 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/result.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/result.py @@ -55,24 +55,24 @@ class GPTModelResult(BaseResult[CompletionResponse], Sequence): model_version: str @classmethod - def _from_proto(cls, message: CompletionResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument + def _from_proto(cls, proto: CompletionResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument alternatives = tuple( Alternative( role=alternative.message.role, text=alternative.message.text, status=AlternativeStatus.from_proto_field(alternative.status), - ) for alternative in message.alternatives + ) for alternative in proto.alternatives ) usage = Usage( - input_text_tokens=message.usage.input_text_tokens, - completion_tokens=message.usage.completion_tokens, - total_tokens=message.usage.total_tokens, + input_text_tokens=proto.usage.input_text_tokens, + completion_tokens=proto.usage.completion_tokens, + total_tokens=proto.usage.total_tokens, ) return cls( alternatives=alternatives, usage=usage, - model_version=message.model_version, + model_version=proto.model_version, ) def __len__(self): diff --git a/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py b/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py index 401ad53..1d10eb5 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py +++ b/src/yandex_cloud_ml_sdk/_models/text_classifiers/result.py @@ -31,17 +31,17 @@ class TextClassifiersModelResultBase(BaseResult[TextClassificationResponseT], Se model_version: str @classmethod - def _from_proto(cls, message: TextClassificationResponseT, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument + def _from_proto(cls, proto: TextClassificationResponseT, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument predictions = tuple( TextClassificationLabel( label=p.label, confidence=p.confidence - ) for p in message.predictions + ) for p in proto.predictions ) return cls( predictions=predictions, - model_version=message.model_version, + model_version=proto.model_version, ) def __len__(self) -> int: diff --git a/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py b/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py index 72e69c8..218028e 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py +++ b/src/yandex_cloud_ml_sdk/_models/text_embeddings/result.py @@ -23,11 +23,11 @@ class TextEmbeddingsModelResult(BaseResult[TextEmbeddingResponse], Sequence): model_version: str @classmethod - def _from_proto(cls, message: TextEmbeddingResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument + def _from_proto(cls, proto: TextEmbeddingResponse, sdk: BaseSDK) -> Self: # pylint: disable=unused-argument return cls( - embedding=tuple(message.embedding), - num_tokens=message.num_tokens, - model_version=message.model_version, + embedding=tuple(proto.embedding), + num_tokens=proto.num_tokens, + model_version=proto.model_version, ) def __len__(self) -> int: diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index b64a076..5ce9a99 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -17,18 +17,21 @@ from ._models import AsyncModels, BaseModels, Models from ._retry import RetryPolicy from ._runs.domain import AsyncRuns, BaseRuns, Runs +from ._search_indexes.domain import AsyncSearchIndexes, BaseSearchIndexes, SearchIndexes from ._threads.domain import AsyncThreads, BaseThreads, Threads from ._types.domain import BaseDomain from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined class BaseSDK: - _messages: BaseMessages models: BaseModels threads: BaseThreads files: BaseFiles assistants: BaseAssistants runs: BaseRuns + search_indexes: BaseSearchIndexes + + _messages: BaseMessages def __init__( self, @@ -143,6 +146,7 @@ class AsyncYCloudML(BaseSDK): threads: AsyncThreads assistants: AsyncAssistants runs: AsyncRuns + search_indexes: AsyncSearchIndexes _messages: AsyncMessages @@ -152,4 +156,5 @@ class YCloudML(BaseSDK): threads: Threads assistants: Assistants runs: Runs + search_indexes: SearchIndexes _messages: Messages diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/__init__.py b/src/yandex_cloud_ml_sdk/_search_indexes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/chunking_strategy.py b/src/yandex_cloud_ml_sdk/_search_indexes/chunking_strategy.py new file mode 100644 index 0000000..742cbf9 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_search_indexes/chunking_strategy.py @@ -0,0 +1,56 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import abc +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from yandex.cloud.ai.assistants.v1.searchindex.common_pb2 import ChunkingStrategy as ProtoChunkingStrategy +from yandex.cloud.ai.assistants.v1.searchindex.common_pb2 import StaticChunkingStrategy as ProtoStaticChunkingStrategy + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + + +class BaseIndexChunkingStrategy(abc.ABC): + @classmethod + @abc.abstractmethod + def _from_proto(cls, proto: Any, sdk: BaseSDK) -> BaseIndexChunkingStrategy: + pass + + @abc.abstractmethod + def _to_proto(self) -> ProtoChunkingStrategy: + pass + + @classmethod + def _from_upper_proto(cls, proto: ProtoChunkingStrategy, sdk: BaseSDK) -> BaseIndexChunkingStrategy: + if proto.HasField('static_strategy'): + return StaticIndexChunkingStrategy._from_proto( + proto=proto.static_strategy, + sdk=sdk + ) + raise NotImplementedError('chunking strategies other then static are not supported in this SDK version') + + +@dataclass(frozen=True) +class StaticIndexChunkingStrategy(BaseIndexChunkingStrategy): + max_chunk_size_tokens: int + + chunk_overlap_tokens: int + + @classmethod + # pylint: disable=unused-argument + def _from_proto(cls, proto: ProtoStaticChunkingStrategy, sdk: BaseSDK) -> StaticIndexChunkingStrategy: + return cls( + max_chunk_size_tokens=proto.max_chunk_size_tokens, + chunk_overlap_tokens=proto.chunk_overlap_tokens + ) + + def _to_proto(self) -> ProtoChunkingStrategy: + return ProtoChunkingStrategy( + static_strategy=ProtoStaticChunkingStrategy( + max_chunk_size_tokens=self.max_chunk_size_tokens, + chunk_overlap_tokens=self.chunk_overlap_tokens + ) + ) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py new file mode 100644 index 0000000..488dd91 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py @@ -0,0 +1,151 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from typing import AsyncIterator, Generic + +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import SearchIndex as ProtoSearchIndex +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import TextSearchIndex, VectorSearchIndex +from yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2 import ( + CreateSearchIndexRequest, GetSearchIndexRequest, ListSearchIndicesRequest, ListSearchIndicesResponse +) +from yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2_grpc import SearchIndexServiceStub +from yandex.cloud.operation.operation_pb2 import Operation as ProtoOperation + +from yandex_cloud_ml_sdk._files.utils import FileType, coerce_file_ids +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined +from yandex_cloud_ml_sdk._types.operation import AsyncOperation, Operation, OperationTypeT +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .index_type import BaseSearchIndexType, TextSearchIndexType, VectorSearchIndexType +from .search_index import AsyncSearchIndex, SearchIndex, SearchIndexTypeT + + +class BaseSearchIndexes(BaseDomain, Generic[SearchIndexTypeT, OperationTypeT]): + _impl: type[SearchIndexTypeT] + _operation_type: type[OperationTypeT] + + # pylint: disable=too-many-locals + async def _create_deferred( + self, + files: FileType, + *, + index_type: UndefinedOr[BaseSearchIndexType] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> OperationTypeT: + if is_defined(ttl_days) != is_defined(expiration_policy): + raise ValueError("ttl_days and expiration policy must be both defined either undefined") + + file_ids = coerce_file_ids(files) + + expiration_config = ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) + + vector_search_index: VectorSearchIndex | None = None + text_search_index: TextSearchIndex | None = None + if isinstance(index_type, VectorSearchIndexType): + vector_search_index = index_type._to_proto() + elif isinstance(index_type, TextSearchIndexType): + text_search_index = index_type._to_proto() + elif is_defined(index_type): + raise TypeError('index type must be instance of SearchIndexType') + + request = CreateSearchIndexRequest( + folder_id=self._folder_id, + file_ids=file_ids, + name=get_defined_value(name, ''), + description=get_defined_value(description, ''), + labels=get_defined_value(labels, {}), + expiration_config=expiration_config.to_proto(), + vector_search_index=vector_search_index, + text_search_index=text_search_index, + ) + + async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Create, + request, + timeout=timeout, + expected_type=ProtoOperation, + ) + + return self._operation_type( + id=response.id, + sdk=self._sdk, + result_type=self._impl + ) + + async def _get( + self, + search_index_id: str, + *, + timeout: float = 60, + ) -> SearchIndexTypeT: + # TODO: we need a global per-sdk cache on ids to rule out + # possibility we have two SearchIndexs with same ids but different fields + request = GetSearchIndexRequest(search_index_id=search_index_id) + + async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoSearchIndex, + ) + + return self._impl._from_proto(proto=response, sdk=self._sdk) + + async def _list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[SearchIndexTypeT]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + while True: + request = ListSearchIndicesRequest( + folder_id=self._folder_id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListSearchIndicesResponse, + ) + for search_index_proto in response.indices: + yield self._impl._from_proto(proto=search_index_proto, sdk=self._sdk) + + if not response.indices: + return + + page_token_ = response.next_page_token + + +class AsyncSearchIndexes(BaseSearchIndexes[AsyncSearchIndex, AsyncOperation[AsyncSearchIndex]]): + _impl = AsyncSearchIndex + _operation_type = AsyncOperation + + get = BaseSearchIndexes._get + create_deferred = BaseSearchIndexes._create_deferred + list = BaseSearchIndexes._list + + +class SearchIndexes(BaseSearchIndexes[SearchIndex, Operation[AsyncSearchIndex]]): + _impl = SearchIndex + _operation_type = Operation + + get = run_sync(BaseSearchIndexes._get) + create_deferred = run_sync(BaseSearchIndexes._create_deferred) + list = run_sync_generator(BaseSearchIndexes._list) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/file.py b/src/yandex_cloud_ml_sdk/_search_indexes/file.py new file mode 100644 index 0000000..84ae646 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_search_indexes/file.py @@ -0,0 +1,36 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime +from typing import TYPE_CHECKING, Any + +from yandex.cloud.ai.assistants.v1.searchindex.search_index_file_pb2 import SearchIndexFile as ProtoSearchIndexFile + +from yandex_cloud_ml_sdk._types.resource import BaseResource + +from .chunking_strategy import BaseIndexChunkingStrategy + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +@dataclass(frozen=True) +class SearchIndexFile(BaseResource): + search_index_id: str + created_by: str + created_at: datetime + chunking_strategy: BaseIndexChunkingStrategy + + @classmethod + def _kwargs_from_message( + cls, + proto: ProtoSearchIndexFile, # type: ignore[override] + sdk: BaseSDK + ) -> dict[str, Any]: + kwargs = super()._kwargs_from_message(proto, sdk=sdk) + # pylint: disable=protected-access + kwargs['chunking_strategy'] = BaseIndexChunkingStrategy._from_upper_proto( + proto=proto.chunking_strategy, sdk=sdk + ) + return kwargs diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/index_type.py b/src/yandex_cloud_ml_sdk/_search_indexes/index_type.py new file mode 100644 index 0000000..c6f666a --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_search_indexes/index_type.py @@ -0,0 +1,90 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import abc +from dataclasses import dataclass +from typing import TYPE_CHECKING, Union + +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import SearchIndex as ProtoSearchIndex +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import TextSearchIndex, VectorSearchIndex + +from .chunking_strategy import BaseIndexChunkingStrategy + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +ProtoSearchIndexType = Union[TextSearchIndex, VectorSearchIndex] + + +@dataclass(frozen=True) +class BaseSearchIndexType(abc.ABC): + chunking_strategy: BaseIndexChunkingStrategy | None = None + + @classmethod + @abc.abstractmethod + def _from_proto(cls, proto, sdk: BaseSDK) -> BaseSearchIndexType: + pass + + @abc.abstractmethod + def _to_proto(self) -> ProtoSearchIndexType: + pass + + @classmethod + def _from_upper_proto(cls, proto: ProtoSearchIndex, sdk: BaseSDK) -> BaseSearchIndexType: + if proto.HasField('text_search_index'): + return TextSearchIndexType._from_proto( + proto=proto.text_search_index, + sdk=sdk + ) + if proto.HasField('vector_search_index'): + return VectorSearchIndexType._from_proto( + proto=proto.vector_search_index, + sdk=sdk + ) + + raise NotImplementedError('search index types other then text&vector are not supported in this SDK version') + + +@dataclass(frozen=True) +class TextSearchIndexType(BaseSearchIndexType): + @classmethod + def _from_proto(cls, proto: TextSearchIndex, sdk: BaseSDK) -> TextSearchIndexType: + return cls( + chunking_strategy=BaseIndexChunkingStrategy._from_upper_proto( + proto=proto.chunking_strategy, + sdk=sdk, + ) + ) + + def _to_proto(self) -> TextSearchIndex: + chunking_strategy = self.chunking_strategy._to_proto() if self.chunking_strategy else None + return TextSearchIndex( + chunking_strategy=chunking_strategy + ) + + +@dataclass(frozen=True) +class VectorSearchIndexType(BaseSearchIndexType): + doc_embedder_uri: str | None = None + + query_embedder_uri: str | None = None + + @classmethod + def _from_proto(cls, proto: VectorSearchIndex, sdk: BaseSDK) -> VectorSearchIndexType: + return cls( + doc_embedder_uri=proto.doc_embedder_uri, + query_embedder_uri=proto.query_embedder_uri, + chunking_strategy=BaseIndexChunkingStrategy._from_upper_proto( + proto=proto.chunking_strategy, + sdk=sdk, + ) + ) + + def _to_proto(self) -> VectorSearchIndex: + chunking_strategy = self.chunking_strategy._to_proto() if self.chunking_strategy else None + return VectorSearchIndex( + chunking_strategy=chunking_strategy, + doc_embedder_uri=self.doc_embedder_uri or '', + query_embedder_uri=self.query_embedder_uri or '', + ) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py new file mode 100644 index 0000000..3e48460 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py @@ -0,0 +1,194 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import dataclasses +from datetime import datetime +from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar + +from typing_extensions import Self +from yandex.cloud.ai.assistants.v1.searchindex.search_index_file_pb2 import SearchIndexFile as ProtoSearchIndexFile +from yandex.cloud.ai.assistants.v1.searchindex.search_index_file_service_pb2 import ( + GetSearchIndexFileRequest, ListSearchIndexFilesRequest, ListSearchIndexFilesResponse +) +from yandex.cloud.ai.assistants.v1.searchindex.search_index_file_service_pb2_grpc import SearchIndexFileServiceStub +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import SearchIndex as ProtoSearchIndex +from yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2 import ( + DeleteSearchIndexRequest, DeleteSearchIndexResponse, UpdateSearchIndexRequest +) +from yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2_grpc import SearchIndexServiceStub + +from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._types.resource import ExpirableResource, safe_on_delete +from yandex_cloud_ml_sdk._types.result import BaseResult +from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator + +from .file import SearchIndexFile +from .index_type import BaseSearchIndexType + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +@dataclasses.dataclass(frozen=True) +class BaseSearchIndex(ExpirableResource, BaseResult[ProtoSearchIndex]): # type: ignore[misc] + _proto_result_type = ProtoSearchIndex + + @classmethod + def _kwargs_from_message(cls, proto: ProtoSearchIndex, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) + # pylint: disable=protected-access + kwargs['index_type'] = BaseSearchIndexType._from_upper_proto(proto=proto, sdk=sdk) + return kwargs + + @safe_on_delete + async def _update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + # pylint: disable=too-many-locals + name_ = get_defined_value(name, '') + description_ = get_defined_value(description, '') + labels_ = get_defined_value(labels, {}) + expiration_config = ExpirationConfig.coerce( + ttl_days=ttl_days, + expiration_policy=expiration_policy + ) + + request = UpdateSearchIndexRequest( + search_index_id=self.id, + name=name_, + description=description_, + labels=labels_, + expiration_config=expiration_config.to_proto(), + ) + + self._fill_update_mask( + request.update_mask, + { + 'description': description, + 'name': name, # this line is moved to avoid "duplicate-code" check of pylint XD + 'labels': labels, + 'expiration_config.ttl_days': ttl_days, + 'expiration_config.expiration_policy': expiration_policy + } + ) + + async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Update, + request, + timeout=timeout, + expected_type=ProtoSearchIndex, + ) + self._update_from_proto(response) + + return self + + @safe_on_delete + async def _delete( + self, + *, + timeout: float = 60, + ) -> None: + request = DeleteSearchIndexRequest(search_index_id=self.id) + + async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + await self._client.call_service( + stub.Delete, + request, + timeout=timeout, + expected_type=DeleteSearchIndexResponse, + ) + object.__setattr__(self, '_deleted', True) + + @safe_on_delete + async def _get_file( + self, + file_id: str, + *, + timeout: float = 60 + ) -> SearchIndexFile: + request = GetSearchIndexFileRequest( + file_id=file_id, + search_index_id=self.id + ) + + async with self._client.get_service_stub(SearchIndexFileServiceStub, timeout=timeout) as stub: + response = await self._client.call_service( + stub.Get, + request, + timeout=timeout, + expected_type=ProtoSearchIndexFile, + ) + + return SearchIndexFile._from_proto(proto=response, sdk=self._sdk) + + async def _list_files( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[SearchIndexFile]: + page_token_ = get_defined_value(page_token, '') + page_size_ = get_defined_value(page_size, 0) + + async with self._client.get_service_stub(SearchIndexFileServiceStub, timeout=timeout) as stub: + while True: + request = ListSearchIndexFilesRequest( + search_index_id=self.id, + page_size=page_size_, + page_token=page_token_, + ) + + response = await self._client.call_service( + stub.List, + request, + timeout=timeout, + expected_type=ListSearchIndexFilesResponse, + ) + for search_index_proto in response.files: + yield SearchIndexFile._from_proto(proto=search_index_proto, sdk=self._sdk) + + if not response.files: + return + + page_token_ = response.next_page_token + + +@dataclasses.dataclass(frozen=True) +class RichSearchIndex(BaseSearchIndex): + folder_id: str + name: str | None + description: str | None + created_by: str + created_at: datetime + updated_by: str + updated_at: datetime + expires_at: datetime + labels: dict[str, str] | None + index_type: BaseSearchIndexType + + +class AsyncSearchIndex(RichSearchIndex): + update = RichSearchIndex._update + delete = RichSearchIndex._delete + get_file = RichSearchIndex._get_file + list_files = RichSearchIndex._list_files + + +class SearchIndex(RichSearchIndex): + update = run_sync(RichSearchIndex._update) + delete = run_sync(RichSearchIndex._delete) + get_file = run_sync(RichSearchIndex._get_file) + list_files = run_sync_generator(RichSearchIndex._list_files) + + +SearchIndexTypeT = TypeVar('SearchIndexTypeT', bound=BaseSearchIndex) diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py index 965325b..cfed46c 100644 --- a/src/yandex_cloud_ml_sdk/_threads/thread.py +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar +from typing import AsyncIterator, TypeVar from typing_extensions import Self from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread @@ -15,26 +15,12 @@ from yandex_cloud_ml_sdk._messages.message import Message from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value -from yandex_cloud_ml_sdk._types.resource import BaseDeleteableResource, safe_on_delete +from yandex_cloud_ml_sdk._types.resource import ExpirableResource, safe_on_delete from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator -if TYPE_CHECKING: - from yandex_cloud_ml_sdk._sdk import BaseSDK - @dataclasses.dataclass(frozen=True) -class BaseThread(BaseDeleteableResource): - expiration_config: ExpirationConfig - - @classmethod - def _kwargs_from_message(cls, proto: ProtoThread, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] - kwargs = super()._kwargs_from_message(proto, sdk=sdk) - kwargs['expiration_config'] = ExpirationConfig.coerce( - ttl_days=proto.expiration_config.ttl_days, - expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] - ) - return kwargs - +class BaseThread(ExpirableResource): @safe_on_delete async def _update( self, diff --git a/src/yandex_cloud_ml_sdk/_types/expiration.py b/src/yandex_cloud_ml_sdk/_types/expiration.py index e6e0316..515213c 100644 --- a/src/yandex_cloud_ml_sdk/_types/expiration.py +++ b/src/yandex_cloud_ml_sdk/_types/expiration.py @@ -1,14 +1,22 @@ +# pylint: disable=no-name-in-module from __future__ import annotations from dataclasses import dataclass from enum import Enum from typing import Literal, Union -# pylint: disable-next=no-name-in-module +from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant +from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import SearchIndex +from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread from yandex.cloud.ai.common.common_pb2 import ExpirationConfig as ExpirationConfigProto +from yandex.cloud.ai.files.v1.file_pb2 import File from .misc import UndefinedOr, get_defined_value +# NB: I wanted to make it a Protocol, with expiration_config field, +# but it loses information about Message inheritance +ExpirationProtoType = Union[Assistant, SearchIndex, Thread, File] + class ExpirationPolicy(Enum): STATIC = ExpirationConfigProto.STATIC diff --git a/src/yandex_cloud_ml_sdk/_types/model.py b/src/yandex_cloud_ml_sdk/_types/model.py index e80d9d1..d1c765a 100644 --- a/src/yandex_cloud_ml_sdk/_types/model.py +++ b/src/yandex_cloud_ml_sdk/_types/model.py @@ -6,7 +6,7 @@ from .misc import Undefined from .model_config import BaseModelConfig -from .operation import BaseOperation +from .operation import OperationTypeT from .result import BaseResult if TYPE_CHECKING: @@ -17,7 +17,6 @@ ConfigTypeT = TypeVar('ConfigTypeT', bound=BaseModelConfig) ResultTypeT = TypeVar('ResultTypeT', bound=BaseResult) -OperationTypeT = TypeVar('OperationTypeT', bound=BaseOperation) class BaseModel(Generic[ConfigTypeT, ResultTypeT], metaclass=abc.ABCMeta): diff --git a/src/yandex_cloud_ml_sdk/_types/operation.py b/src/yandex_cloud_ml_sdk/_types/operation.py index ec91cd5..a01b535 100644 --- a/src/yandex_cloud_ml_sdk/_types/operation.py +++ b/src/yandex_cloud_ml_sdk/_types/operation.py @@ -1,3 +1,4 @@ +# pylint: disable=protected-access from __future__ import annotations import abc @@ -124,7 +125,7 @@ async def _get_result(self, *, timeout=60) -> ResultTypeT: # NB: mypy can't figure out that self._result_type._from_proto is # returning instance of self._result_type which is also is a ResultTypeT - return cast(ResultTypeT, self._result_type._from_proto(proto_result, sdk=self._sdk)) + return cast(ResultTypeT, self._result_type._from_proto(proto=proto_result, sdk=self._sdk)) if status.is_failed: assert status.error is not None @@ -155,16 +156,34 @@ async def _cancel(self, *, timeout=60) -> OperationStatus: ) return status + async def _wait( + self, + *, + timeout: int = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> ResultTypeT: + # NB: mypy doesn't resolve generic type ResultTypeT in case of inheritance, + # so, just recopy this method here + return await super()._wait( + timeout=timeout, + poll_interval=poll_interval, + poll_timeout=poll_timeout, + ) + -class AsyncOperation(BaseOperation): +class AsyncOperation(BaseOperation[ResultTypeT]): get_status = BaseOperation._get_status get_result = BaseOperation._get_result wait = BaseOperation._wait cancel = BaseOperation._cancel -class Operation(BaseOperation): +class Operation(BaseOperation[ResultTypeT]): get_status = run_sync(BaseOperation._get_status) get_result = run_sync(BaseOperation._get_result) wait = run_sync(BaseOperation._wait) cancel = run_sync(BaseOperation._cancel) + + +OperationTypeT = TypeVar('OperationTypeT', bound=BaseOperation) diff --git a/src/yandex_cloud_ml_sdk/_types/resource.py b/src/yandex_cloud_ml_sdk/_types/resource.py index f5e481b..00044ab 100644 --- a/src/yandex_cloud_ml_sdk/_types/resource.py +++ b/src/yandex_cloud_ml_sdk/_types/resource.py @@ -11,6 +11,7 @@ from yandex_cloud_ml_sdk._utils.proto import proto_to_dict +from .expiration import ExpirationConfig, ExpirationProtoType from .misc import is_defined if TYPE_CHECKING: @@ -78,6 +79,20 @@ def _from_proto(cls, *, sdk: BaseSDK, proto: Message) -> Self: ) +@dataclasses.dataclass(frozen=True) +class ExpirableResource(BaseDeleteableResource): + expiration_config: ExpirationConfig + + @classmethod + def _kwargs_from_message(cls, proto: ExpirationProtoType, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] + kwargs = super()._kwargs_from_message(proto, sdk=sdk) # type: ignore[arg-type] + kwargs['expiration_config'] = ExpirationConfig.coerce( + ttl_days=proto.expiration_config.ttl_days, + expiration_policy=proto.expiration_config.expiration_policy, # type: ignore[arg-type] + ) + return kwargs + + P = ParamSpec('P') T = TypeVar('T') R = TypeVar('R', bound=BaseDeleteableResource) diff --git a/src/yandex_cloud_ml_sdk/_types/result.py b/src/yandex_cloud_ml_sdk/_types/result.py index a34c2d7..fceef09 100644 --- a/src/yandex_cloud_ml_sdk/_types/result.py +++ b/src/yandex_cloud_ml_sdk/_types/result.py @@ -18,5 +18,5 @@ class BaseResult(abc.ABC, Generic[ProtoResultTypeT]): @classmethod @abc.abstractmethod - def _from_proto(cls: type[Self], message: ProtoResultTypeT, sdk: BaseSDK) -> Self: + def _from_proto(cls: type[Self], proto: ProtoResultTypeT, sdk: BaseSDK) -> Self: raise NotImplementedError() diff --git a/src/yandex_cloud_ml_sdk/search_indexes.py b/src/yandex_cloud_ml_sdk/search_indexes.py new file mode 100644 index 0000000..197d284 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/search_indexes.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from ._search_indexes.chunking_strategy import StaticIndexChunkingStrategy +from ._search_indexes.index_type import TextSearchIndexType, VectorSearchIndexType + +__all__ = [ + 'StaticIndexChunkingStrategy', + 'VectorSearchIndexType', + 'TextSearchIndexType' +] diff --git a/tests/assistants/cassettes/test_search_indexes/test_search_index.gprc.json b/tests/assistants/cassettes/test_search_indexes/test_search_index.gprc.json new file mode 100644 index 0000000..9659664 --- /dev/null +++ b/tests/assistants/cassettes/test_search_indexes/test_search_index.gprc.json @@ -0,0 +1,770 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvt42bkvkv8p8blq6kod", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.569100Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:34.569100Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.569100Z" + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvt42bkvkv8p8blq6kod" + ] + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrl0rd50u7b0plskht", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:34.713711Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:34.713711Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtrl0rd50u7b0plskht" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrl0rd50u7b0plskht", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:34.713711Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:34.713711Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtrl0rd50u7b0plskht" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrl0rd50u7b0plskht", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:34.713711Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:35.370730Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtbtobvouuiv6gk9m44", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.703122Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:34.703122Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.703122Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "GetSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtbtobvouuiv6gk9m44" + } + }, + "response": { + "cls": "SearchIndex", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2", + "message": { + "id": "fvtbtobvouuiv6gk9m44", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.703122Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:34.703122Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.703122Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvt42bkvkv8p8blq6kod" + ], + "vectorSearchIndex": {} + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1lkkhc04dbb392hil", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:44.988867Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:44.988867Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt1lkkhc04dbb392hil" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1lkkhc04dbb392hil", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:44.988867Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:44.988867Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt1lkkhc04dbb392hil" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1lkkhc04dbb392hil", + "description": "search index creation", + "createdAt": "2024-10-30T17:28:44.988867Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:28:46.308402Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt7gc2p6c81lcdicdka", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:44.978882Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:44.978882Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:44.978882Z", + "vectorSearchIndex": { + "docEmbedderUri": "emb://yc.ml.rag-prod.common/text-search-doc/latest", + "queryEmbedderUri": "emb://yc.ml.rag-prod.common/text-search-query/latest", + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "UpdateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtbtobvouuiv6gk9m44", + "updateMask": "name", + "name": "name" + } + }, + "response": { + "cls": "SearchIndex", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2", + "message": { + "id": "fvtbtobvouuiv6gk9m44", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.703122Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:55.205825Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.703122Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + }, + { + "request": { + "cls": "UpdateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtbtobvouuiv6gk9m44", + "updateMask": "description", + "description": "description" + } + }, + "response": { + "cls": "SearchIndex", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2", + "message": { + "id": "fvtbtobvouuiv6gk9m44", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.703122Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:55.276859Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.703122Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + }, + { + "request": { + "cls": "UpdateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtbtobvouuiv6gk9m44", + "updateMask": "labels", + "labels": { + "foo": "bar" + } + } + }, + "response": { + "cls": "SearchIndex", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2", + "message": { + "id": "fvtbtobvouuiv6gk9m44", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "name", + "description": "description", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:34.703122Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:55.310433Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:34.703122Z", + "labels": { + "foo": "bar" + }, + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvt42bkvkv8p8blq6kod" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtbtobvouuiv6gk9m44" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_search_indexes/test_search_index_deleted.gprc.json b/tests/assistants/cassettes/test_search_indexes/test_search_index_deleted.gprc.json new file mode 100644 index 0000000..1e02d05 --- /dev/null +++ b/tests/assistants/cassettes/test_search_indexes/test_search_index_deleted.gprc.json @@ -0,0 +1,529 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtpl0la8ksufgp00ncv", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:31:25.377866Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:31:25.377866Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:31:25.377866Z" + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvtpl0la8ksufgp00ncv" + ] + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkaq2tfmdaj4bfm89p", + "description": "search index creation", + "createdAt": "2024-10-30T17:31:25.570374Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:31:25.570374Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtkaq2tfmdaj4bfm89p" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkaq2tfmdaj4bfm89p", + "description": "search index creation", + "createdAt": "2024-10-30T17:31:25.570374Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:31:25.570374Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtkaq2tfmdaj4bfm89p" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkaq2tfmdaj4bfm89p", + "description": "search index creation", + "createdAt": "2024-10-30T17:31:25.570374Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:31:26.194516Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtsojk01g818kngobfq", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:31:25.541672Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:31:25.541672Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:31:25.541672Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtsojk01g818kngobfq" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtpl0la8ksufgp00ncv" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/cassettes/test_search_indexes/test_search_index_list.gprc.json b/tests/assistants/cassettes/test_search_indexes/test_search_index_list.gprc.json new file mode 100644 index 0000000..cc52e16 --- /dev/null +++ b/tests/assistants/cassettes/test_search_indexes/test_search_index_list.gprc.json @@ -0,0 +1,2140 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "dGVzdCBmaWxl" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvte7h3e4u5bo3tkk7t0", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:06.361039Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:06.361039Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:06.361039Z" + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ] + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt2pt8rv5igf3sghivk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:06.534181Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:06.534181Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt2pt8rv5igf3sghivk" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt2pt8rv5igf3sghivk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:06.534181Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:06.534181Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt2pt8rv5igf3sghivk" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt2pt8rv5igf3sghivk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:06.534181Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:07.121050Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtvi63l544pcehvaite", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:06.523856Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:06.523856Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:06.523856Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s0" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1vcgcemj72qs1qrqj", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:16.713011Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:16.713011Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt1vcgcemj72qs1qrqj" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1vcgcemj72qs1qrqj", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:16.713011Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:16.713011Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt1vcgcemj72qs1qrqj" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt1vcgcemj72qs1qrqj", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:16.713011Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:17.240869Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtj41mj8uu02tvvh1i5", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:16.701222Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:16.701222Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:16.701222Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s1" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtmmavlk4tddri6rojk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:26.905105Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:26.905105Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtmmavlk4tddri6rojk" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtmmavlk4tddri6rojk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:26.905105Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:26.905105Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtmmavlk4tddri6rojk" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtmmavlk4tddri6rojk", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:26.905105Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:27.268515Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtmed4eflqf36igsub6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:26.895233Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:26.895233Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:26.895233Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s2" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtjr1u5rco3akehju45", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:37.075022Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:37.075022Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtjr1u5rco3akehju45" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtjr1u5rco3akehju45", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:37.075022Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:37.075022Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtjr1u5rco3akehju45" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtjr1u5rco3akehju45", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:37.075022Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:37.527901Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt7tulbln91gtl3nk9b", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:37.063620Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:37.063620Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:37.063620Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s3" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt0c1ljk97n2ge0435d", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:47.222949Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:47.222949Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt0c1ljk97n2ge0435d" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt0c1ljk97n2ge0435d", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:47.222949Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:47.222949Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvt0c1ljk97n2ge0435d" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvt0c1ljk97n2ge0435d", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:47.222949Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:47.831505Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtephv9opbcsh1b54qf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s3", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:47.193797Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:47.193797Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:47.193797Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s4" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtd96bkmkhbl37knuer", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:57.421158Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:57.421158Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtd96bkmkhbl37knuer" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtd96bkmkhbl37knuer", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:57.421158Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:57.421158Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtd96bkmkhbl37knuer" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtd96bkmkhbl37knuer", + "description": "search index creation", + "createdAt": "2024-10-30T17:29:57.421158Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:29:58.243796Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt52cpch12sj7t36902", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s4", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:57.369565Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:57.369565Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:57.369565Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s5" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtemrmep2pbpbvejnhe", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:07.585510Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:07.585510Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtemrmep2pbpbvejnhe" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtemrmep2pbpbvejnhe", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:07.585510Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:07.585510Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtemrmep2pbpbvejnhe" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtemrmep2pbpbvejnhe", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:07.585510Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:08.103364Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvti1jm94iontbaqea46", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s5", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:07.574545Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:07.574545Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:07.574545Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s6" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtcsgocft7f6avdqbj2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:17.746958Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:17.746958Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtcsgocft7f6avdqbj2" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtcsgocft7f6avdqbj2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:17.746958Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:17.746958Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtcsgocft7f6avdqbj2" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtcsgocft7f6avdqbj2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:17.746958Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:18.192046Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt86tvb9p3ln5oblhkv", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s6", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:17.717751Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:17.717751Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:17.717751Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s7" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkgl9nr273t4f283qo", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:27.929926Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:27.929926Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtkgl9nr273t4f283qo" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkgl9nr273t4f283qo", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:27.929926Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:27.929926Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtkgl9nr273t4f283qo" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtkgl9nr273t4f283qo", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:27.929926Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:28.537471Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt4i7qqpns501o0p5fh", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:27.918772Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:27.918772Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:27.918772Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s8" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvth4obk2nkel54o9k9d", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:38.076416Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:38.076416Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvth4obk2nkel54o9k9d" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvth4obk2nkel54o9k9d", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:38.076416Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:38.076416Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvth4obk2nkel54o9k9d" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvth4obk2nkel54o9k9d", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:38.076416Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:38.469324Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtr06ep4309t8di2i5b", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s8", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:38.065293Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:38.065293Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:38.065293Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvte7h3e4u5bo3tkk7t0" + ], + "name": "s9" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrko49u7rre0npk0l2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:48.282103Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:48.282103Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtrko49u7rre0npk0l2" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrko49u7rre0npk0l2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:48.282103Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:48.282103Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvtrko49u7rre0npk0l2" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvtrko49u7rre0npk0l2", + "description": "search index creation", + "createdAt": "2024-10-30T17:30:48.282103Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T17:30:48.769330Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvt32gj2cva31ochdfjf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s9", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:48.230545Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:48.230545Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:48.230545Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "ListSearchIndicesRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "ListSearchIndicesResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "indices": [ + { + "id": "fvt32gj2cva31ochdfjf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s9", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:48.230545Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:48.230545Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:48.230545Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtr06ep4309t8di2i5b", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s8", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:38.065293Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:38.065293Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:38.065293Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt4i7qqpns501o0p5fh", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s7", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:27.918772Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:27.918772Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:27.918772Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt86tvb9p3ln5oblhkv", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s6", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:17.717751Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:17.717751Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:17.717751Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvti1jm94iontbaqea46", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s5", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:30:07.574545Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:30:07.574545Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:30:07.574545Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt52cpch12sj7t36902", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s4", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:57.369565Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:57.369565Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:57.369565Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtephv9opbcsh1b54qf", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s3", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:47.193797Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:47.193797Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:47.193797Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt7tulbln91gtl3nk9b", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s2", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:37.063620Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:37.063620Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:37.063620Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtmed4eflqf36igsub6", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s1", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:26.895233Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:26.895233Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:26.895233Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtj41mj8uu02tvvh1i5", + "folderId": "b1ghsjum2v37c2un8h64", + "name": "s0", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:16.701222Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:16.701222Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:16.701222Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtvi63l544pcehvaite", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:29:06.523856Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:29:06.523856Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:29:06.523856Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt7gc2p6c81lcdicdka", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:28:44.978882Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:28:44.978882Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:28:44.978882Z", + "vectorSearchIndex": { + "docEmbedderUri": "emb://yc.ml.rag-prod.common/text-search-doc/latest", + "queryEmbedderUri": "emb://yc.ml.rag-prod.common/text-search-query/latest", + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtskqvcjcsu3jb53qh5", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:25:49.365095Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:25:49.365095Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:25:49.365095Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt3lcbmvsabos61cdh4", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:24:37.913321Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:24:37.913321Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:24:37.913321Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtagnpene84ri1gko74", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:24:37.414805Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:24:37.414805Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:24:37.414805Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvt4glg110v81phvnn9l", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T17:24:36.679743Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T17:24:36.679743Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T17:24:36.679743Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + }, + { + "id": "fvtv5q8tf9rrcqjruqk6", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T15:50:06.183955Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T15:50:06.183955Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T15:50:06.183955Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "700", + "chunkOverlapTokens": "300" + } + } + } + }, + { + "id": "fvtst4r1foav6uh2bl2n", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T15:47:39.580262Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T15:47:39.580262Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T15:47:39.580262Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "700", + "chunkOverlapTokens": "300" + } + } + } + }, + { + "id": "fvt9gqo4i706qen6abp4", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T15:45:16.052930Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T15:45:16.052930Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T15:45:16.052930Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "700", + "chunkOverlapTokens": "300" + } + } + } + }, + { + "id": "fvtjsiq2svr08htf8bcj", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T15:43:52.281311Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T15:43:52.281311Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T15:43:52.281311Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "700", + "chunkOverlapTokens": "300" + } + } + } + } + ], + "nextPageToken": "MjAyNC0xMC0zMFQxNTo0Mzo1Mi4yODEzMTFAZnZ0anNpcTJzdnIwOGh0ZjhiY2o=" + } + } + }, + { + "request": { + "cls": "ListSearchIndicesRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "pageToken": "MjAyNC0xMC0zMFQxNTo0Mzo1Mi4yODEzMTFAZnZ0anNpcTJzdnIwOGh0ZjhiY2o=" + } + }, + "response": { + "cls": "ListSearchIndicesResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt32gj2cva31ochdfjf" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtr06ep4309t8di2i5b" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt4i7qqpns501o0p5fh" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt86tvb9p3ln5oblhkv" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvti1jm94iontbaqea46" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt52cpch12sj7t36902" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtephv9opbcsh1b54qf" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt7tulbln91gtl3nk9b" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtmed4eflqf36igsub6" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtj41mj8uu02tvvh1i5" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtvi63l544pcehvaite" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt7gc2p6c81lcdicdka" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtskqvcjcsu3jb53qh5" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt3lcbmvsabos61cdh4" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtagnpene84ri1gko74" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt4glg110v81phvnn9l" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtv5q8tf9rrcqjruqk6" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtst4r1foav6uh2bl2n" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvt9gqo4i706qen6abp4" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtjsiq2svr08htf8bcj" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvte7h3e4u5bo3tkk7t0" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_search_indexes.py b/tests/assistants/test_search_indexes.py new file mode 100644 index 0000000..c9fa21a --- /dev/null +++ b/tests/assistants/test_search_indexes.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +import pytest + +from yandex_cloud_ml_sdk.search_indexes import StaticIndexChunkingStrategy, TextSearchIndexType, VectorSearchIndexType + +pytestmark = pytest.mark.asyncio + + +@pytest.fixture(name='test_file_path') +def fixture_test_file_path(tmp_path): + path = tmp_path / 'test_file' + path.write_bytes(b'test file') + yield path + + +@pytest.mark.allow_grpc +@pytest.mark.vcr +async def test_search_index(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + operation = await async_sdk.search_indexes.create_deferred(file) + search_index = await operation.wait() + + search_index2 = await async_sdk.search_indexes.get(search_index.id) + assert search_index2.id == search_index.id + # I hope is temporary + assert search_index2 is not search_index + + assert isinstance(search_index.index_type, TextSearchIndexType) + assert isinstance(search_index.index_type.chunking_strategy, StaticIndexChunkingStrategy) + + operation = await async_sdk.search_indexes.create_deferred(file.id, index_type=VectorSearchIndexType()) + search_index3 = await operation.wait() + assert isinstance(search_index3.index_type, VectorSearchIndexType) + + for field, value in ( + ('name', 'name'), + ('description', 'description'), + ('labels', {'foo': 'bar'}), + ): + assert getattr(search_index, field) is None + + new_search_index = await search_index.update( + **{field: value} + ) + + assert new_search_index is search_index + + assert getattr(search_index, field) == value + + await file.delete() + await search_index.delete() + + +@pytest.mark.allow_grpc +async def test_search_index_deleted(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + operation = await async_sdk.search_indexes.create_deferred(file) + search_index = await operation.wait() + + await search_index.delete() + + for method in ('delete', 'update'): + with pytest.raises(ValueError): + await getattr(search_index, method)() + + await file.delete() + + +@pytest.mark.allow_grpc +async def test_search_index_list(async_sdk, test_file_path): + file = await async_sdk.files.upload(test_file_path) + operation = await async_sdk.search_indexes.create_deferred(file) + search_index = await operation.wait() + created_search_indexes = [] + for i in range(10): + operation = await async_sdk.search_indexes.create_deferred([file], name=f"s{i}") + search_index = await operation.wait() + created_search_indexes.append(search_index) + + present_search_indexes = set() + search_indexes = [f async for f in async_sdk.search_indexes.list()] + for search_index in search_indexes: + present_search_indexes.add(search_index.id) + + for i, search_index in enumerate(created_search_indexes): + if search_index.id not in present_search_indexes: + continue + + assert search_index.name == f's{i}' + + for search_index in search_indexes: + await search_index.delete() + + await file.delete() diff --git a/tests/conftest.py b/tests/conftest.py index 2695b53..4aa7f28 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -141,9 +141,10 @@ def fixture_async_sdk( interceptors=interceptors, auth=auth, retry_policy=retry_policy, - service_map={ + service_map={ # TMP 'ai-files': 'assistant.api.cloud.yandex.net', 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'operation': 'assistant.api.cloud.yandex.net', } ) if test_client: From d7ce7efb0830bcb5980ee0c894c0a1daa37de2ad Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Thu, 31 Oct 2024 14:17:12 +0100 Subject: [PATCH 08/13] Assistants tools (#10) --- .../assistants/assistant_with_search_index.py | 62 ++ examples/async/assistants/search_query.txt | 4 +- .../_assistants/assistant.py | 7 + src/yandex_cloud_ml_sdk/_assistants/domain.py | 13 +- src/yandex_cloud_ml_sdk/_files/utils.py | 20 - src/yandex_cloud_ml_sdk/_sdk.py | 4 + .../_search_indexes/domain.py | 7 +- src/yandex_cloud_ml_sdk/_tools/__init__.py | 0 src/yandex_cloud_ml_sdk/_tools/domain.py | 24 + src/yandex_cloud_ml_sdk/_tools/tool.py | 63 ++ src/yandex_cloud_ml_sdk/_utils/coerce.py | 44 + ...test_assistant_with_search_index.gprc.json | 826 ++++++++++++++++++ tests/assistants/test_search_indexes.py | 25 + 13 files changed, 1071 insertions(+), 28 deletions(-) create mode 100755 examples/async/assistants/assistant_with_search_index.py delete mode 100644 src/yandex_cloud_ml_sdk/_files/utils.py create mode 100644 src/yandex_cloud_ml_sdk/_tools/__init__.py create mode 100644 src/yandex_cloud_ml_sdk/_tools/domain.py create mode 100644 src/yandex_cloud_ml_sdk/_tools/tool.py create mode 100644 src/yandex_cloud_ml_sdk/_utils/coerce.py create mode 100644 tests/assistants/cassettes/test_search_indexes/test_assistant_with_search_index.gprc.json diff --git a/examples/async/assistants/assistant_with_search_index.py b/examples/async/assistants/assistant_with_search_index.py new file mode 100755 index 0000000..d598a2f --- /dev/null +++ b/examples/async/assistants/assistant_with_search_index.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import asyncio +import pathlib + +from yandex_cloud_ml_sdk import AsyncYCloudML + + +def local_path(path: str) -> pathlib.Path: + return pathlib.Path(__file__).parent / path + + +async def main() -> None: + sdk = AsyncYCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'ai-files': 'assistant.api.cloud.yandex.net', + 'operation': 'assistant.api.cloud.yandex.net', + } + ) + + file_coros = ( + sdk.files.upload( + local_path(path), + ttl_days=5, + expiration_policy="static", + ) + for path in ['turkey_example.txt', 'maldives_example.txt'] + ) + + files = await asyncio.gather(*file_coros) + operation = await sdk.search_indexes.create_deferred(files) + search_index = await operation.wait() + + tool = sdk.tools.search_index(search_index) + + assistant = await sdk.assistants.create('yandexgpt', tools=[tool]) + thread = await sdk.threads.create() + + for search_query in ( + local_path('search_query.txt').read_text().splitlines()[0], + "Cколько пошлина в Анталье" + ): + await thread.write(search_query) + run = await assistant.run(thread) + result = await run + print('Question', search_query) + print('Answer:', result.text) + + await search_index.delete() + await thread.delete() + await assistant.delete() + + for file in files: + await file.delete() + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/examples/async/assistants/search_query.txt b/examples/async/assistants/search_query.txt index feea401..a9126d1 100644 --- a/examples/async/assistants/search_query.txt +++ b/examples/async/assistants/search_query.txt @@ -1,3 +1 @@ -Какова стоимость выездной пошлины для путешествия в чарующие и солнечные МАЛЬДИВЫ, -где беззаботный отдых на восхитительных пляжах, утопающих в лучах мягкого средиземноморского солнца, -соединяется с открытием величественных исторических памятников и наслаждением изысканными ароматами местной кухни? +Какова стоимость выездной пошлины для путешествия в чарующие и солнечные МАЛЬДИВЫ, где беззаботный отдых на восхитительных пляжах, утопающих в лучах мягкого средиземноморского солнца, соединяется с открытием величественных исторических памятников и наслаждением изысканными ароматами местной кухни? diff --git a/src/yandex_cloud_ml_sdk/_assistants/assistant.py b/src/yandex_cloud_ml_sdk/_assistants/assistant.py index 06234bf..d1623e7 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/assistant.py +++ b/src/yandex_cloud_ml_sdk/_assistants/assistant.py @@ -16,6 +16,7 @@ from yandex_cloud_ml_sdk._models.completions.model import BaseGPTModel from yandex_cloud_ml_sdk._runs.run import AsyncRun, Run, RunTypeT from yandex_cloud_ml_sdk._threads.thread import AsyncThread, Thread, ThreadTypeT +from yandex_cloud_ml_sdk._tools.tool import BaseTool from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._types.resource import ExpirableResource, safe_on_delete @@ -33,6 +34,7 @@ class BaseAssistant(ExpirableResource, Generic[RunTypeT, ThreadTypeT]): model: BaseGPTModel instruction: str | None max_prompt_tokens: int | None + tools: tuple[BaseTool, ...] @classmethod def _kwargs_from_message(cls, proto: ProtoAssistant, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override] @@ -45,6 +47,11 @@ def _kwargs_from_message(cls, proto: ProtoAssistant, sdk: BaseSDK) -> dict[str, model = model.configure(temperature=temperature) kwargs['model'] = model + kwargs['tools'] = tuple( + BaseTool._from_upper_proto(tool, sdk=sdk) + for tool in proto.tools + ) + if max_prompt_tokens := proto.prompt_truncation_options.max_prompt_tokens.value: kwargs['max_prompt_tokens'] = max_prompt_tokens diff --git a/src/yandex_cloud_ml_sdk/_assistants/domain.py b/src/yandex_cloud_ml_sdk/_assistants/domain.py index ca07762..c4c64c1 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/domain.py +++ b/src/yandex_cloud_ml_sdk/_assistants/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic +from typing import AsyncIterator, Generic, Iterable from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant from yandex.cloud.ai.assistants.v1.assistant_service_pb2 import ( @@ -10,9 +10,11 @@ from yandex.cloud.ai.assistants.v1.assistant_service_pb2_grpc import AssistantServiceStub from yandex_cloud_ml_sdk._models.completions.model import BaseGPTModel +from yandex_cloud_ml_sdk._tools.tool import BaseTool from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined +from yandex_cloud_ml_sdk._utils.coerce import coerce_tuple from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .assistant import Assistant, AssistantTypeT, AsyncAssistant @@ -35,6 +37,7 @@ async def _create( description: UndefinedOr[str] = UNDEFINED, labels: UndefinedOr[dict[str, str]] = UNDEFINED, ttl_days: UndefinedOr[int] = UNDEFINED, + tools: UndefinedOr[Iterable[BaseTool]] = UNDEFINED, expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, timeout: float = 60, ) -> AssistantTypeT: @@ -59,6 +62,11 @@ async def _create( model_temperature = get_defined_value(temperature, model_temperature) model_max_tokens = get_defined_value(max_tokens, model_max_tokens) + tools_: tuple[BaseTool, ...] = () + if is_defined(tools): + # NB: mypy doesn't love abstract class used as TypeVar substitution here + tools_ = coerce_tuple(tools, BaseTool) # type: ignore[type-abstract] + request = CreateAssistantRequest( folder_id=self._folder_id, name=get_defined_value(name, ''), @@ -73,7 +81,8 @@ async def _create( completion_options=get_completion_options( temperature=model_temperature, max_tokens=model_max_tokens - ) + ), + tools=[tool._to_proto() for tool in tools_] ) async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: diff --git a/src/yandex_cloud_ml_sdk/_files/utils.py b/src/yandex_cloud_ml_sdk/_files/utils.py deleted file mode 100644 index 6eeea94..0000000 --- a/src/yandex_cloud_ml_sdk/_files/utils.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -from typing import Iterable, Union - -from .file import BaseFile - -FileType = Union[str, BaseFile, Iterable[BaseFile], Iterable[str]] - - -def coerce_file_ids(files: FileType) -> tuple[str, ...]: - if isinstance(files, str): - return (files, ) - - if isinstance(files, BaseFile): - return (files.id, ) - - return tuple( - file.id if isinstance(file, BaseFile) else file - for file in files - ) diff --git a/src/yandex_cloud_ml_sdk/_sdk.py b/src/yandex_cloud_ml_sdk/_sdk.py index 5ce9a99..590371c 100644 --- a/src/yandex_cloud_ml_sdk/_sdk.py +++ b/src/yandex_cloud_ml_sdk/_sdk.py @@ -19,11 +19,13 @@ from ._runs.domain import AsyncRuns, BaseRuns, Runs from ._search_indexes.domain import AsyncSearchIndexes, BaseSearchIndexes, SearchIndexes from ._threads.domain import AsyncThreads, BaseThreads, Threads +from ._tools.domain import Tools from ._types.domain import BaseDomain from ._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined class BaseSDK: + tools: Tools models: BaseModels threads: BaseThreads files: BaseFiles @@ -141,6 +143,7 @@ def _get_event_loop() -> asyncio.AbstractEventLoop: class AsyncYCloudML(BaseSDK): + tools: Tools models: AsyncModels files: AsyncFiles threads: AsyncThreads @@ -151,6 +154,7 @@ class AsyncYCloudML(BaseSDK): class YCloudML(BaseSDK): + tools: Tools models: Models files: Files threads: Threads diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py index 488dd91..764c76b 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py @@ -11,11 +11,12 @@ from yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2_grpc import SearchIndexServiceStub from yandex.cloud.operation.operation_pb2 import Operation as ProtoOperation -from yandex_cloud_ml_sdk._files.utils import FileType, coerce_file_ids +from yandex_cloud_ml_sdk._files.file import BaseFile from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.expiration import ExpirationConfig, ExpirationPolicyAlias from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value, is_defined from yandex_cloud_ml_sdk._types.operation import AsyncOperation, Operation, OperationTypeT +from yandex_cloud_ml_sdk._utils.coerce import ResourceType, coerce_resource_ids from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .index_type import BaseSearchIndexType, TextSearchIndexType, VectorSearchIndexType @@ -29,7 +30,7 @@ class BaseSearchIndexes(BaseDomain, Generic[SearchIndexTypeT, OperationTypeT]): # pylint: disable=too-many-locals async def _create_deferred( self, - files: FileType, + files: ResourceType[BaseFile], *, index_type: UndefinedOr[BaseSearchIndexType] = UNDEFINED, name: UndefinedOr[str] = UNDEFINED, @@ -42,7 +43,7 @@ async def _create_deferred( if is_defined(ttl_days) != is_defined(expiration_policy): raise ValueError("ttl_days and expiration policy must be both defined either undefined") - file_ids = coerce_file_ids(files) + file_ids = coerce_resource_ids(files, BaseFile) expiration_config = ExpirationConfig.coerce(ttl_days=ttl_days, expiration_policy=expiration_policy) diff --git a/src/yandex_cloud_ml_sdk/_tools/__init__.py b/src/yandex_cloud_ml_sdk/_tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/yandex_cloud_ml_sdk/_tools/domain.py b/src/yandex_cloud_ml_sdk/_tools/domain.py new file mode 100644 index 0000000..495824f --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_tools/domain.py @@ -0,0 +1,24 @@ +# pylint: disable=protected-access,no-name-in-module +from __future__ import annotations + +from yandex_cloud_ml_sdk._search_indexes.search_index import BaseSearchIndex +from yandex_cloud_ml_sdk._types.domain import BaseDomain +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value +from yandex_cloud_ml_sdk._utils.coerce import ResourceType, coerce_resource_ids + +from .tool import SearchIndexTool + + +class Tools(BaseDomain): + def search_index( + self, + indexes: ResourceType[BaseSearchIndex], + *, + max_num_results: UndefinedOr[int] = UNDEFINED, + ): + index_ids = coerce_resource_ids(indexes, BaseSearchIndex) + max_num_results_ = get_defined_value(max_num_results, None) + return SearchIndexTool( + search_index_ids=tuple(index_ids), + max_num_results=max_num_results_ + ) diff --git a/src/yandex_cloud_ml_sdk/_tools/tool.py b/src/yandex_cloud_ml_sdk/_tools/tool.py new file mode 100644 index 0000000..02950d2 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_tools/tool.py @@ -0,0 +1,63 @@ +# pylint: disable=no-name-in-module +from __future__ import annotations + +import abc +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from google.protobuf.wrappers_pb2 import Int64Value +from yandex.cloud.ai.assistants.v1.common_pb2 import SearchIndexTool as ProtoSearchIndexTool +from yandex.cloud.ai.assistants.v1.common_pb2 import Tool as ProtoTool + +if TYPE_CHECKING: + from yandex_cloud_ml_sdk._sdk import BaseSDK + + +class BaseTool(abc.ABC): + @classmethod + @abc.abstractmethod + def _from_proto(cls, proto: Any, sdk: BaseSDK) -> BaseTool: + pass + + @abc.abstractmethod + def _to_proto(self) -> ProtoTool: + pass + + @classmethod + def _from_upper_proto(cls, proto: ProtoTool, sdk: BaseSDK) -> BaseTool: + if proto.HasField('search_index'): + return SearchIndexTool._from_proto( + proto=proto.search_index, + sdk=sdk + ) + raise NotImplementedError('tools other then search_index are not supported in this SDK version') + + +@dataclass(frozen=True) +class SearchIndexTool(BaseTool): + search_index_ids: tuple[str, ...] + + max_num_results: int | None = None + + @classmethod + def _from_proto(cls, proto: ProtoSearchIndexTool, sdk: BaseSDK) -> SearchIndexTool: + max_num_results: int | None = None + if proto.HasField("max_num_results"): + max_num_results = proto.max_num_results.value + + return cls( + search_index_ids=tuple(proto.search_index_ids), + max_num_results=max_num_results, + ) + + def _to_proto(self) -> ProtoTool: + max_num_results: None | Int64Value = None + if self.max_num_results is not None: + max_num_results = Int64Value(value=self.max_num_results) + + return ProtoTool( + search_index=ProtoSearchIndexTool( + max_num_results=max_num_results, + search_index_ids=self.search_index_ids + ) + ) diff --git a/src/yandex_cloud_ml_sdk/_utils/coerce.py b/src/yandex_cloud_ml_sdk/_utils/coerce.py new file mode 100644 index 0000000..f2f1a89 --- /dev/null +++ b/src/yandex_cloud_ml_sdk/_utils/coerce.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from typing import Iterable, TypeVar, Union + +from yandex_cloud_ml_sdk._types.resource import BaseResource + +_T = TypeVar('_T') +ResourceTypeT = TypeVar('ResourceTypeT', bound=BaseResource) +ResourceType = Union[str, ResourceTypeT, Iterable[ResourceTypeT], Iterable[str]] + + +def coerce_resource_ids( + resources: ResourceType[ResourceTypeT], + resource_type: type[ResourceTypeT], +) -> tuple[str, ...]: + if isinstance(resources, str): + return (resources, ) + + if isinstance(resources, resource_type): + return (resources.id, ) + + if not isinstance(resources, Iterable): + raise TypeError(f'{resources} expected to be str, {resource_type} or Iterable') + + result: list[str] = [] + for resource in resources: + if isinstance(resource, resource_type): + result.append(resource.id) + elif isinstance(resource, str): + result.append(resource) + else: + raise TypeError(f'{resource} expected to be str or {resource_type}') + + return tuple(result) + + +def coerce_tuple(value: Iterable[_T] | _T, value_type: type[_T]) -> tuple[_T, ...]: + if isinstance(value, value_type): + return (value, ) + + if not isinstance(value, Iterable): + raise TypeError(f'{value} expected to be {value_type} or Iterable') + + return tuple(value) diff --git a/tests/assistants/cassettes/test_search_indexes/test_assistant_with_search_index.gprc.json b/tests/assistants/cassettes/test_search_indexes/test_assistant_with_search_index.gprc.json new file mode 100644 index 0000000..8e56ba3 --- /dev/null +++ b/tests/assistants/cassettes/test_search_indexes/test_assistant_with_search_index.gprc.json @@ -0,0 +1,826 @@ +{ + "interactions": [ + { + "request": { + "cls": "ListApiEndpointsRequest", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": {} + }, + "response": { + "cls": "ListApiEndpointsResponse", + "module": "yandex.cloud.endpoint.api_endpoint_service_pb2", + "message": { + "endpoints": [ + { + "id": "ai-foundation-models", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-llm", + "address": "llm.api.cloud.yandex.net:443" + }, + { + "id": "ai-speechkit", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt", + "address": "transcribe.api.cloud.yandex.net:443" + }, + { + "id": "ai-stt-v3", + "address": "stt.api.cloud.yandex.net:443" + }, + { + "id": "ai-translate", + "address": "translate.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision", + "address": "vision.api.cloud.yandex.net:443" + }, + { + "id": "ai-vision-ocr", + "address": "ocr.api.cloud.yandex.net:443" + }, + { + "id": "alb", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apigateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "application-load-balancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "apploadbalancer", + "address": "alb.api.cloud.yandex.net:443" + }, + { + "id": "audittrails", + "address": "audittrails.api.cloud.yandex.net:443" + }, + { + "id": "baas", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "backup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "billing", + "address": "billing.api.cloud.yandex.net:443" + }, + { + "id": "broker-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "cdn", + "address": "cdn.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager", + "address": "certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "certificate-manager-data", + "address": "data.certificate-manager.api.cloud.yandex.net:443" + }, + { + "id": "cic", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudapps", + "address": "cloudapps.api.cloud.yandex.net:443" + }, + { + "id": "cloudbackup", + "address": "backup.api.cloud.yandex.net:443" + }, + { + "id": "clouddesktops", + "address": "clouddesktops.api.cloud.yandex.net:443" + }, + { + "id": "cloudrouter", + "address": "cic-api.api.cloud.yandex.net:443" + }, + { + "id": "cloudvideo", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "compute", + "address": "compute.api.cloud.yandex.net:443" + }, + { + "id": "container-registry", + "address": "container-registry.api.cloud.yandex.net:443" + }, + { + "id": "dataproc", + "address": "dataproc.api.cloud.yandex.net:443" + }, + { + "id": "dataproc-manager", + "address": "dataproc-manager.api.cloud.yandex.net:443" + }, + { + "id": "datasphere", + "address": "datasphere.api.cloud.yandex.net:443" + }, + { + "id": "datatransfer", + "address": "datatransfer.api.cloud.yandex.net:443" + }, + { + "id": "dns", + "address": "dns.api.cloud.yandex.net:443" + }, + { + "id": "endpoint", + "address": "api.cloud.yandex.net:443" + }, + { + "id": "iam", + "address": "iam.api.cloud.yandex.net:443" + }, + { + "id": "iot-broker", + "address": "iot-broker.api.cloud.yandex.net:443" + }, + { + "id": "iot-data", + "address": "iot-data.api.cloud.yandex.net:443" + }, + { + "id": "iot-devices", + "address": "iot-devices.api.cloud.yandex.net:443" + }, + { + "id": "k8s", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "kms", + "address": "kms.api.cloud.yandex.net:443" + }, + { + "id": "kms-crypto", + "address": "kms.yandex:443" + }, + { + "id": "load-balancer", + "address": "load-balancer.api.cloud.yandex.net:443" + }, + { + "id": "loadtesting", + "address": "loadtesting.api.cloud.yandex.net:443" + }, + { + "id": "locator", + "address": "locator.api.cloud.yandex.net:443" + }, + { + "id": "lockbox", + "address": "lockbox.api.cloud.yandex.net:443" + }, + { + "id": "lockbox-payload", + "address": "payload.lockbox.api.cloud.yandex.net:443" + }, + { + "id": "log-ingestion", + "address": "ingester.logging.yandexcloud.net:443" + }, + { + "id": "log-reading", + "address": "reader.logging.yandexcloud.net:443" + }, + { + "id": "logging", + "address": "logging.api.cloud.yandex.net:443" + }, + { + "id": "managed-airflow", + "address": "airflow.api.cloud.yandex.net:443" + }, + { + "id": "managed-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-elasticsearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-greenplum", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kafka", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-kubernetes", + "address": "mks.api.cloud.yandex.net:443" + }, + { + "id": "managed-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "managed-sqlserver", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "marketplace", + "address": "marketplace.api.cloud.yandex.net:443" + }, + { + "id": "mdb-clickhouse", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mongodb", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-mysql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-opensearch", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-postgresql", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdb-redis", + "address": "mdb.api.cloud.yandex.net:443" + }, + { + "id": "mdbproxy", + "address": "mdbproxy.api.cloud.yandex.net:443" + }, + { + "id": "monitoring", + "address": "monitoring.api.cloud.yandex.net:443" + }, + { + "id": "operation", + "address": "operation.api.cloud.yandex.net:443" + }, + { + "id": "organization-manager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "organizationmanager", + "address": "organization-manager.api.cloud.yandex.net:443" + }, + { + "id": "resource-manager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "resourcemanager", + "address": "resource-manager.api.cloud.yandex.net:443" + }, + { + "id": "searchapi", + "address": "searchapi.api.cloud.yandex.net:443" + }, + { + "id": "serialssh", + "address": "serialssh.cloud.yandex.net:9600" + }, + { + "id": "serverless-apigateway", + "address": "serverless-apigateway.api.cloud.yandex.net:443" + }, + { + "id": "serverless-containers", + "address": "serverless-containers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-eventrouter", + "address": "serverless-eventrouter.api.cloud.yandex.net:443" + }, + { + "id": "serverless-functions", + "address": "serverless-functions.api.cloud.yandex.net:443" + }, + { + "id": "serverless-gateway-connections", + "address": "apigateway-connections.api.cloud.yandex.net:443" + }, + { + "id": "serverless-triggers", + "address": "serverless-triggers.api.cloud.yandex.net:443" + }, + { + "id": "serverless-workflows", + "address": "serverless-workflows.api.cloud.yandex.net:443" + }, + { + "id": "serverlesseventrouter-events", + "address": "events.eventrouter.serverless.yandexcloud.net:443" + }, + { + "id": "smart-captcha", + "address": "smartcaptcha.api.cloud.yandex.net:443" + }, + { + "id": "smart-web-security", + "address": "smartwebsecurity.api.cloud.yandex.net:443" + }, + { + "id": "storage", + "address": "storage.yandexcloud.net:443" + }, + { + "id": "storage-api", + "address": "storage.api.cloud.yandex.net:443" + }, + { + "id": "video", + "address": "video.api.cloud.yandex.net:443" + }, + { + "id": "vpc", + "address": "vpc.api.cloud.yandex.net:443" + }, + { + "id": "ydb", + "address": "ydb.api.cloud.yandex.net:443" + } + ] + } + } + }, + { + "request": { + "cls": "CreateFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "content": "bXkgc2VjcmV0IG51bWJlciBpcyA1Nw==" + } + }, + "response": { + "cls": "File", + "module": "yandex.cloud.ai.files.v1.file_pb2", + "message": { + "id": "fvtkl1qldovmp9li86pq", + "folderId": "b1ghsjum2v37c2un8h64", + "mimeType": "text/plain", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:48.478939Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T20:06:48.478939Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T20:06:48.478939Z" + } + } + }, + { + "request": { + "cls": "CreateSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "fileIds": [ + "fvtkl1qldovmp9li86pq" + ] + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvts4jr9bsuu2hk5vuod", + "description": "search index creation", + "createdAt": "2024-10-30T20:06:48.623200Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T20:06:48.623200Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvts4jr9bsuu2hk5vuod" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvts4jr9bsuu2hk5vuod", + "description": "search index creation", + "createdAt": "2024-10-30T20:06:48.623200Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T20:06:48.623200Z" + } + } + }, + { + "request": { + "cls": "GetOperationRequest", + "module": "yandex.cloud.operation.operation_service_pb2", + "message": { + "operationId": "fvts4jr9bsuu2hk5vuod" + } + }, + "response": { + "cls": "Operation", + "module": "yandex.cloud.operation.operation_pb2", + "message": { + "id": "fvts4jr9bsuu2hk5vuod", + "description": "search index creation", + "createdAt": "2024-10-30T20:06:48.623200Z", + "createdBy": "ajek27c96hekgf8f8016", + "modifiedAt": "2024-10-30T20:06:49.416081Z", + "done": true, + "response": { + "@type": "type.googleapis.com/yandex.cloud.ai.assistants.v1.searchindex.SearchIndex", + "id": "fvtg66didrhp0q8qf5op", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:48.612906Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T20:06:48.612906Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T20:06:48.612906Z", + "textSearchIndex": { + "chunkingStrategy": { + "staticStrategy": { + "maxChunkSizeTokens": "800", + "chunkOverlapTokens": "400" + } + } + } + } + } + } + }, + { + "request": { + "cls": "CreateAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {}, + "tools": [ + { + "searchIndex": { + "searchIndexIds": [ + "fvtg66didrhp0q8qf5op" + ] + } + } + ] + } + }, + "response": { + "cls": "Assistant", + "module": "yandex.cloud.ai.assistants.v1.assistant_pb2", + "message": { + "id": "fvt74a317bubotma2p73", + "folderId": "b1ghsjum2v37c2un8h64", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:58.892073Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T20:06:58.892073Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T20:06:58.892073Z", + "modelUri": "gpt://b1ghsjum2v37c2un8h64/yandexgpt/latest", + "promptTruncationOptions": {}, + "completionOptions": {}, + "tools": [ + { + "searchIndex": { + "searchIndexIds": [ + "fvtg66didrhp0q8qf5op" + ] + } + } + ] + } + } + }, + { + "request": { + "cls": "CreateThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "folderId": "b1ghsjum2v37c2un8h64" + } + }, + "response": { + "cls": "Thread", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_pb2", + "message": { + "id": "fvt98brdvp2vsklh8u30", + "folderId": "b1ghsjum2v37c2un8h64", + "defaultMessageAuthorId": "fvtae47kdue7d9kmolpb", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.010797Z", + "updatedBy": "ajek27c96hekgf8f8016", + "updatedAt": "2024-10-30T20:06:59.010797Z", + "expirationConfig": { + "expirationPolicy": "SINCE_LAST_ACTIVE", + "ttlDays": "7" + }, + "expiresAt": "2024-11-06T20:06:59.010797Z" + } + } + }, + { + "request": { + "cls": "CreateMessageRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.message_service_pb2", + "message": { + "threadId": "fvt98brdvp2vsklh8u30", + "content": { + "content": [ + { + "text": { + "content": "what is your secret number" + } + } + ] + } + } + }, + "response": { + "cls": "Message", + "module": "yandex.cloud.ai.assistants.v1.threads.message_pb2", + "message": { + "id": "fvtjomekahaiftoupmfe", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.118293Z", + "author": { + "id": "fvtae47kdue7d9kmolpb", + "role": "USER" + }, + "content": { + "content": [ + { + "text": { + "content": "what is your secret number" + } + } + ] + } + } + } + }, + { + "request": { + "cls": "CreateRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "assistantId": "fvt74a317bubotma2p73", + "threadId": "fvt98brdvp2vsklh8u30", + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvttbem2dpo3pbc5bdk1", + "assistantId": "fvt74a317bubotma2p73", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.214265963Z", + "state": { + "status": "PENDING" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvttbem2dpo3pbc5bdk1" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvttbem2dpo3pbc5bdk1", + "assistantId": "fvt74a317bubotma2p73", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.214265963Z", + "state": { + "status": "IN_PROGRESS" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvttbem2dpo3pbc5bdk1" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvttbem2dpo3pbc5bdk1", + "assistantId": "fvt74a317bubotma2p73", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.214265963Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvt3grb142drnue3cb5r", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.691747393Z", + "author": { + "id": "fvt74a317bubotma2p73", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "57" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "41", + "completionTokens": "4", + "totalTokens": "45" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "GetRunRequest", + "module": "yandex.cloud.ai.assistants.v1.runs.run_service_pb2", + "message": { + "runId": "fvttbem2dpo3pbc5bdk1" + } + }, + "response": { + "cls": "Run", + "module": "yandex.cloud.ai.assistants.v1.runs.run_pb2", + "message": { + "id": "fvttbem2dpo3pbc5bdk1", + "assistantId": "fvt74a317bubotma2p73", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.214265963Z", + "state": { + "status": "COMPLETED", + "completedMessage": { + "id": "fvt3grb142drnue3cb5r", + "threadId": "fvt98brdvp2vsklh8u30", + "createdBy": "ajek27c96hekgf8f8016", + "createdAt": "2024-10-30T20:06:59.691747393Z", + "author": { + "id": "fvt74a317bubotma2p73", + "role": "ASSISTANT" + }, + "content": { + "content": [ + { + "text": { + "content": "57" + } + } + ] + } + } + }, + "usage": { + "promptTokens": "41", + "completionTokens": "4", + "totalTokens": "45" + }, + "customPromptTruncationOptions": {}, + "customCompletionOptions": {} + } + } + }, + { + "request": { + "cls": "DeleteSearchIndexRequest", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": { + "searchIndexId": "fvtg66didrhp0q8qf5op" + } + }, + "response": { + "cls": "DeleteSearchIndexResponse", + "module": "yandex.cloud.ai.assistants.v1.searchindex.search_index_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteThreadRequest", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": { + "threadId": "fvt98brdvp2vsklh8u30" + } + }, + "response": { + "cls": "DeleteThreadResponse", + "module": "yandex.cloud.ai.assistants.v1.threads.thread_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteAssistantRequest", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": { + "assistantId": "fvt74a317bubotma2p73" + } + }, + "response": { + "cls": "DeleteAssistantResponse", + "module": "yandex.cloud.ai.assistants.v1.assistant_service_pb2", + "message": {} + } + }, + { + "request": { + "cls": "DeleteFileRequest", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": { + "fileId": "fvtkl1qldovmp9li86pq" + } + }, + "response": { + "cls": "DeleteFileResponse", + "module": "yandex.cloud.ai.files.v1.file_service_pb2", + "message": {} + } + } + ] +} diff --git a/tests/assistants/test_search_indexes.py b/tests/assistants/test_search_indexes.py index c9fa21a..bb786be 100644 --- a/tests/assistants/test_search_indexes.py +++ b/tests/assistants/test_search_indexes.py @@ -93,3 +93,28 @@ async def test_search_index_list(async_sdk, test_file_path): await search_index.delete() await file.delete() + + +@pytest.mark.allow_grpc +async def test_assistant_with_search_index(async_sdk, tmp_path): + raw_file = tmp_path / 'file' + raw_file.write_text('my secret number is 57') + + file = await async_sdk.files.upload(raw_file) + operation = await async_sdk.search_indexes.create_deferred(file) + search_index = await operation.wait() + tool = async_sdk.tools.search_index(search_index) + + assistant = await async_sdk.assistants.create('yandexgpt', tools=[tool]) + thread = await async_sdk.threads.create() + await thread.write('what is your secret number') + + run = await assistant.run(thread) + result = await run + + assert result.text == '57' + + await search_index.delete() + await thread.delete() + await assistant.delete() + await file.delete() From 3f193712044240b46dd565b9f5db5c0fa269595e Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Thu, 31 Oct 2024 20:43:33 +0100 Subject: [PATCH 09/13] Copypaste methods signatures in favor of autocompletion (#11) --- src/yandex_cloud_ml_sdk/_assistants/domain.py | 123 +++++++++++++- src/yandex_cloud_ml_sdk/_files/domain.py | 154 +++++++++++++++++- src/yandex_cloud_ml_sdk/_files/file.py | 106 +++++++++++- src/yandex_cloud_ml_sdk/_messages/domain.py | 89 +++++++++- .../_models/completions/message.py | 3 +- .../_models/completions/model.py | 132 +++++++++++++-- .../_models/text_classifiers/model.py | 43 ++++- .../_models/text_embeddings/model.py | 32 +++- src/yandex_cloud_ml_sdk/_runs/domain.py | 105 +++++++++--- src/yandex_cloud_ml_sdk/_runs/run.py | 87 ++++++++-- .../_search_indexes/domain.py | 107 +++++++++++- .../_search_indexes/search_index.py | 114 ++++++++++++- src/yandex_cloud_ml_sdk/_threads/domain.py | 97 ++++++++++- src/yandex_cloud_ml_sdk/_threads/thread.py | 112 +++++++++++-- src/yandex_cloud_ml_sdk/_types/operation.py | 72 ++++++-- 15 files changed, 1234 insertions(+), 142 deletions(-) diff --git a/src/yandex_cloud_ml_sdk/_assistants/domain.py b/src/yandex_cloud_ml_sdk/_assistants/domain.py index c4c64c1..d473810 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/domain.py +++ b/src/yandex_cloud_ml_sdk/_assistants/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic, Iterable +from typing import AsyncIterator, Generic, Iterable, Iterator from yandex.cloud.ai.assistants.v1.assistant_pb2 import Assistant as ProtoAssistant from yandex.cloud.ai.assistants.v1.assistant_service_pb2 import ( @@ -151,14 +151,123 @@ async def _list( class AsyncAssistants(BaseAssistants[AsyncAssistant]): _assistant_impl = AsyncAssistant - get = BaseAssistants._get - create = BaseAssistants._create - list = BaseAssistants._list + # pylint: disable=too-many-arguments + async def create( + self, + model: str | BaseGPTModel, + *, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + tools: UndefinedOr[Iterable[BaseTool]] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncAssistant: + return await self._create( + model=model, + temperature=temperature, + max_tokens=max_tokens, + instruction=instruction, + max_prompt_tokens=max_prompt_tokens, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + tools=tools, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + async def get( + self, + assistant_id: str, + *, + timeout: float = 60, + ) -> AsyncAssistant: + return await self._get( + assistant_id=assistant_id, + timeout=timeout + ) + + async def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AsyncAssistant]: + async for assistant in self._list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ): + yield assistant class Assistants(BaseAssistants[Assistant]): _assistant_impl = Assistant - get = run_sync(BaseAssistants._get) - create = run_sync(BaseAssistants._create) - list = run_sync_generator(BaseAssistants._list) + __get = run_sync(BaseAssistants._get) + __create = run_sync(BaseAssistants._create) + __list = run_sync_generator(BaseAssistants._list) + + # pylint: disable=too-many-arguments + def create( + self, + model: str | BaseGPTModel, + *, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED, + instruction: UndefinedOr[str] = UNDEFINED, + max_prompt_tokens: UndefinedOr[int] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + tools: UndefinedOr[Iterable[BaseTool]] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Assistant: + return self.__create( + model=model, + temperature=temperature, + max_tokens=max_tokens, + instruction=instruction, + max_prompt_tokens=max_prompt_tokens, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + tools=tools, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + def get( + self, + assistant_id: str, + *, + timeout: float = 60, + ) -> Assistant: + return self.__get( + assistant_id=assistant_id, + timeout=timeout + ) + + def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[Assistant]: + yield from self.__list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_files/domain.py b/src/yandex_cloud_ml_sdk/_files/domain.py index 46c8b28..2596595 100644 --- a/src/yandex_cloud_ml_sdk/_files/domain.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic +from typing import AsyncIterator, Generic, Iterator from yandex.cloud.ai.files.v1.file_pb2 import File as ProtoFile from yandex.cloud.ai.files.v1.file_service_pb2 import ( @@ -137,16 +137,152 @@ async def _list( class AsyncFiles(BaseFiles[AsyncFile]): _file_impl = AsyncFile - upload = BaseFiles._upload - upload_bytes = BaseFiles._upload_bytes - get = BaseFiles._get - list = BaseFiles._list + async def upload_bytes( + self, + data: bytes, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncFile: + return await self._upload_bytes( + data=data, + name=name, + description=description, + mime_type=mime_type, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + async def upload( + self, + path: PathLike, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncFile: + return await self._upload( + path=path, + name=name, + description=description, + mime_type=mime_type, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + async def get( + self, + file_id: str, + *, + timeout: float = 60, + ) -> AsyncFile: + return await self._get( + file_id=file_id, + timeout=timeout + ) + + async def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AsyncFile]: + async for file in self._list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ): + yield file class Files(BaseFiles[File]): _file_impl = File - upload = run_sync(BaseFiles._upload) - upload_bytes = run_sync(BaseFiles._upload_bytes) - get = run_sync(BaseFiles._get) - list = run_sync_generator(BaseFiles._list) + __upload = run_sync(BaseFiles._upload) + __upload_bytes = run_sync(BaseFiles._upload_bytes) + __get = run_sync(BaseFiles._get) + __list = run_sync_generator(BaseFiles._list) + + def upload_bytes( + self, + data: bytes, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> File: + return self.__upload_bytes( + data=data, + name=name, + description=description, + mime_type=mime_type, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + def upload( + self, + path: PathLike, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + mime_type: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> File: + return self.__upload( + path=path, + name=name, + description=description, + mime_type=mime_type, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + def get( + self, + file_id: str, + *, + timeout: float = 60, + ) -> File: + return self.__get( + file_id=file_id, + timeout=timeout + ) + + def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[File]: + yield from self.__list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_files/file.py b/src/yandex_cloud_ml_sdk/_files/file.py index d8041dc..e9f9734 100644 --- a/src/yandex_cloud_ml_sdk/_files/file.py +++ b/src/yandex_cloud_ml_sdk/_files/file.py @@ -141,17 +141,107 @@ class RichFile(BaseFile): class AsyncFile(RichFile): - get_url = RichFile._get_url - update = RichFile._update - delete = RichFile._delete - download_as_bytes = RichFile._download_as_bytes + async def get_url( + self, + *, + timeout: float = 60 + ) -> str: + return await self._get_url( + timeout=timeout + ) + + async def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncFile: + return await self._update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + async def delete( + self, + *, + timeout: float = 60, + ) -> None: + await self._delete( + timeout=timeout + ) + + async def download_as_bytes( + self, + *, + chunk_size: int = 32768, + timeout: float = 60 + ) -> bytes: + return await self._download_as_bytes( + chunk_size=chunk_size, + timeout=timeout + ) class File(RichFile): - get_url = run_sync(RichFile._get_url) - update = run_sync(RichFile._update) - delete = run_sync(RichFile._delete) - download_as_bytes = run_sync(RichFile._download_as_bytes) + __get_url = run_sync(RichFile._get_url) + __update = run_sync(RichFile._update) + __delete = run_sync(RichFile._delete) + __download_as_bytes = run_sync(RichFile._download_as_bytes) + def get_url( + self, + *, + timeout: float = 60 + ) -> str: + return self.__get_url( + timeout=timeout + ) + + def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> File: + return self.__update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + def delete( + self, + *, + timeout: float = 60, + ) -> None: + self.__delete( + timeout=timeout + ) + + def download_as_bytes( + self, + *, + chunk_size: int = 32768, + timeout: float = 60 + ) -> bytes: + return self.__download_as_bytes( + chunk_size=chunk_size, + timeout=timeout + ) FileTypeT = TypeVar('FileTypeT', bound=BaseFile) diff --git a/src/yandex_cloud_ml_sdk/_messages/domain.py b/src/yandex_cloud_ml_sdk/_messages/domain.py index 776ab4e..3970982 100644 --- a/src/yandex_cloud_ml_sdk/_messages/domain.py +++ b/src/yandex_cloud_ml_sdk/_messages/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator +from typing import AsyncIterator, Iterator from yandex.cloud.ai.assistants.v1.threads.message_pb2 import ContentPart from yandex.cloud.ai.assistants.v1.threads.message_pb2 import Message as ProtoMessage @@ -89,12 +89,87 @@ async def _list( class AsyncMessages(BaseMessages): - get = BaseMessages._get - create = BaseMessages._create - list = BaseMessages._list + async def create( + self, + content: str, + *, + thread_id: str, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + return await self._create( + content=content, + thread_id=thread_id, + labels=labels, + timeout=timeout + ) + + async def get( + self, + *, + thread_id: str, + message_id: str, + timeout: float = 60, + ) -> Message: + return await self._get( + thread_id=thread_id, + message_id=message_id, + timeout=timeout + ) + + async def list( + self, + *, + thread_id: str, + timeout: float = 60 + ) -> AsyncIterator[Message]: + async for message in self._list( + thread_id=thread_id, + timeout=timeout + ): + yield message class Messages(BaseMessages): - get = run_sync(BaseMessages._get) - create = run_sync(BaseMessages._create) - list = run_sync_generator(BaseMessages._list) + __get = run_sync(BaseMessages._get) + __create = run_sync(BaseMessages._create) + __list = run_sync_generator(BaseMessages._list) + + def create( + self, + content: str, + *, + thread_id: str, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + return self.__create( + content=content, + thread_id=thread_id, + labels=labels, + timeout=timeout + ) + + def get( + self, + *, + thread_id: str, + message_id: str, + timeout: float = 60, + ) -> Message: + return self.__get( + thread_id=thread_id, + message_id=message_id, + timeout=timeout + ) + + def list( + self, + *, + thread_id: str, + timeout: float = 60 + ) -> Iterator[Message]: + yield from self.__list( + thread_id=thread_id, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_models/completions/message.py b/src/yandex_cloud_ml_sdk/_models/completions/message.py index a00361a..50543ec 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/message.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/message.py @@ -18,9 +18,10 @@ class TextMessageDict(TypedDict): text: str MessageType = Union[TextMessage, TextMessageDict, str] +MessageInputType = Union[MessageType, Iterable[MessageType]] -def messages_to_proto(messages: MessageType | Iterable[MessageType]) -> list[ProtoMessage]: +def messages_to_proto(messages: MessageInputType) -> list[ProtoMessage]: msgs: Iterable[MessageType] if isinstance(messages, (dict, str, TextMessage)): # NB: dict is also Iterable, so techically messages could be a dict[MessageType, str] diff --git a/src/yandex_cloud_ml_sdk/_models/completions/model.py b/src/yandex_cloud_ml_sdk/_models/completions/model.py index 8e1c144..22386a7 100644 --- a/src/yandex_cloud_ml_sdk/_models/completions/model.py +++ b/src/yandex_cloud_ml_sdk/_models/completions/model.py @@ -1,9 +1,9 @@ # pylint: disable=arguments-renamed,no-name-in-module,protected-access from __future__ import annotations -from typing import TYPE_CHECKING, Any, AsyncIterator, Iterable, Literal +from typing import TYPE_CHECKING, Any, AsyncIterator, Iterator, Literal -from typing_extensions import override +from typing_extensions import Self, override from yandex.cloud.ai.foundation_models.v1.text_common_pb2 import CompletionOptions from yandex.cloud.ai.foundation_models.v1.text_generation.text_generation_service_pb2 import ( CompletionRequest, CompletionResponse, TokenizeResponse @@ -13,12 +13,13 @@ ) from yandex.cloud.operation.operation_pb2 import Operation as ProtoOperation +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr from yandex_cloud_ml_sdk._types.model import ModelAsyncMixin, ModelSyncMixin, ModelSyncStreamMixin, OperationTypeT from yandex_cloud_ml_sdk._types.operation import AsyncOperation, Operation from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator from .config import GPTModelConfig -from .message import MessageType, messages_to_proto +from .message import MessageInputType, messages_to_proto from .result import GPTModelResult from .token import Token @@ -44,10 +45,22 @@ def langchain(self, model_type: Literal["chat"] = "chat", timeout: int = 60) -> raise ValueError(f"unknown langchain model {type=}") + # pylint: disable=useless-parent-delegation,arguments-differ + def configure( # type: ignore[override] + self, + *, + temperature: UndefinedOr[float] = UNDEFINED, + max_tokens: UndefinedOr[int] = UNDEFINED + ) -> Self: + return super().configure( + temperature=temperature, + max_tokens=max_tokens + ) + def _make_request( self, *, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, stream: bool | None, ) -> CompletionRequest: completion_options_kwargs: dict[str, Any] = {} @@ -69,7 +82,7 @@ def _make_request( async def _run_sync_impl( self, *, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, stream: bool, timeout: int, ) -> AsyncIterator[GPTModelResult]: @@ -93,7 +106,7 @@ async def _run_sync_impl( # pylint: disable-next=arguments-differ async def _run( self, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, *, timeout=60, ) -> GPTModelResult: @@ -110,7 +123,7 @@ async def _run( # pylint: disable-next=arguments-differ async def _run_stream( self, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, *, timeout=60, ) -> AsyncIterator[GPTModelResult]: @@ -127,7 +140,7 @@ async def _run_stream( # pylint: disable-next=arguments-differ async def _run_deferred( self, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, *, timeout=60 ) -> OperationTypeT: @@ -158,7 +171,7 @@ def attach_async(self, operation_id: str) -> OperationTypeT: async def _tokenize( self, - messages: MessageType | Iterable[MessageType], + messages: MessageInputType, *, timeout=60 ) -> tuple[Token, ...]: @@ -177,16 +190,101 @@ async def _tokenize( class AsyncGPTModel(BaseGPTModel[AsyncOperation[GPTModelResult]]): - run = BaseGPTModel._run - run_stream = BaseGPTModel._run_stream - run_deferred = BaseGPTModel._run_deferred - tokenize = BaseGPTModel._tokenize _operation_type = AsyncOperation + async def run( + self, + messages: MessageInputType, + *, + timeout=60, + ) -> GPTModelResult: + return await self._run( + messages=messages, + timeout=timeout + ) + + async def run_stream( + self, + messages: MessageInputType, + *, + timeout=60, + ) -> AsyncIterator[GPTModelResult]: + async for result in self._run_stream( + messages=messages, + timeout=timeout + ): + yield result + + async def run_deferred( + self, + messages: MessageInputType, + *, + timeout=60 + ) -> AsyncOperation[GPTModelResult]: + return await self._run_deferred( + messages=messages, + timeout=timeout, + ) + + async def tokenize( + self, + messages: MessageInputType, + *, + timeout=60 + ) -> tuple[Token, ...]: + return await self._tokenize( + messages=messages, + timeout=timeout + ) + class GPTModel(BaseGPTModel[Operation[GPTModelResult]]): - run = run_sync(BaseGPTModel._run) - run_stream = run_sync_generator(BaseGPTModel._run_stream) - run_deferred = run_sync(BaseGPTModel._run_deferred) - tokenize = run_sync(BaseGPTModel._tokenize) _operation_type = Operation + __run = run_sync(BaseGPTModel._run) + __run_stream = run_sync_generator(BaseGPTModel._run_stream) + __run_deferred = run_sync(BaseGPTModel._run_deferred) + __tokenize = run_sync(BaseGPTModel._tokenize) + + def run( + self, + messages: MessageInputType, + *, + timeout=60, + ) -> GPTModelResult: + return self.__run( + messages=messages, + timeout=timeout + ) + + def run_stream( + self, + messages: MessageInputType, + *, + timeout=60, + ) -> Iterator[GPTModelResult]: + yield from self.__run_stream( + messages=messages, + timeout=timeout + ) + + def run_deferred( + self, + messages: MessageInputType, + *, + timeout=60 + ) -> Operation[GPTModelResult]: + return self.__run_deferred( + messages=messages, + timeout=timeout, + ) + + def tokenize( + self, + messages: MessageInputType, + *, + timeout=60 + ) -> tuple[Token, ...]: + return self.__tokenize( + messages=messages, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py b/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py index 028bbf5..6b3ebee 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py +++ b/src/yandex_cloud_ml_sdk/_models/text_classifiers/model.py @@ -2,8 +2,9 @@ from __future__ import annotations from dataclasses import astuple +from typing import Sequence -from typing_extensions import override +from typing_extensions import Self, override from yandex.cloud.ai.foundation_models.v1.text_classification.text_classification_pb2 import ( ClassificationSample as TextClassificationSampleProto ) @@ -15,11 +16,13 @@ TextClassificationServiceStub ) +from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr from yandex_cloud_ml_sdk._types.model import ModelSyncMixin from yandex_cloud_ml_sdk._utils.sync import run_sync from .config import TextClassifiersModelConfig from .result import FewShotTextClassifiersModelResult, TextClassifiersModelResult, TextClassifiersModelResultBase +from .types import TextClassificationSample class BaseTextClassifiersModel( @@ -28,6 +31,20 @@ class BaseTextClassifiersModel( _config_type = TextClassifiersModelConfig _result_type = TextClassifiersModelResultBase + # pylint: disable=useless-parent-delegation,arguments-differ + def configure( # type: ignore[override] + self, + *, + task_description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[Sequence[str]] = UNDEFINED, + samples: UndefinedOr[Sequence[TextClassificationSample]] = UNDEFINED, + ) -> Self: + return super().configure( + task_description=task_description, + labels=labels, + samples=samples, + ) + @override # pylint: disable-next=arguments-differ async def _run( @@ -104,8 +121,28 @@ async def _run_few_shot( class AsyncTextClassifiersModel(BaseTextClassifiersModel): - run = BaseTextClassifiersModel._run + async def run( + self, + text: str, + *, + timeout: float = 60, + ) -> TextClassifiersModelResultBase: + return await self._run( + text=text, + timeout=timeout + ) class TextClassifiersModel(BaseTextClassifiersModel): - run = run_sync(BaseTextClassifiersModel._run) + __run = run_sync(BaseTextClassifiersModel._run) + + def run( + self, + text: str, + *, + timeout: float = 60, + ) -> TextClassifiersModelResultBase: + return self.__run( + text=text, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py b/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py index 43a08fd..9a48c9e 100644 --- a/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py +++ b/src/yandex_cloud_ml_sdk/_models/text_embeddings/model.py @@ -1,7 +1,7 @@ # pylint: disable=arguments-renamed,no-name-in-module from __future__ import annotations -from typing_extensions import override +from typing_extensions import Self, override from yandex.cloud.ai.foundation_models.v1.embedding.embedding_service_pb2 import ( TextEmbeddingRequest, TextEmbeddingResponse ) @@ -20,6 +20,12 @@ class BaseTextEmbeddingsModel( _config_type = TextEmbeddingsModelConfig _result_type = TextEmbeddingsModelResult + # pylint: disable=useless-parent-delegation,arguments-differ + def configure( # type: ignore[override] + self, + ) -> Self: + return super().configure() + def _make_request( self, *, @@ -52,8 +58,28 @@ async def _run( class AsyncTextEmbeddingsModel(BaseTextEmbeddingsModel): - run = BaseTextEmbeddingsModel._run + async def run( + self, + text: str, + *, + timeout=60, + ) -> TextEmbeddingsModelResult: + return await self._run( + text=text, + timeout=timeout + ) class TextEmbeddingsModel(BaseTextEmbeddingsModel): - run = run_sync(BaseTextEmbeddingsModel._run) + __run = run_sync(BaseTextEmbeddingsModel._run) + + def run( + self, + text: str, + *, + timeout=60, + ) -> TextEmbeddingsModelResult: + return self.__run( + text=text, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_runs/domain.py b/src/yandex_cloud_ml_sdk/_runs/domain.py index 04b53eb..fb30c42 100644 --- a/src/yandex_cloud_ml_sdk/_runs/domain.py +++ b/src/yandex_cloud_ml_sdk/_runs/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic +from typing import AsyncIterator, Generic, Iterator from yandex.cloud.ai.assistants.v1.runs.run_pb2 import Run as ProtoRun from yandex.cloud.ai.assistants.v1.runs.run_service_pb2 import ( @@ -9,9 +9,9 @@ ) from yandex.cloud.ai.assistants.v1.runs.run_service_pb2_grpc import RunServiceStub -from yandex_cloud_ml_sdk._assistants.assistant import Assistant, AssistantTypeT, AsyncAssistant, BaseAssistant +from yandex_cloud_ml_sdk._assistants.assistant import BaseAssistant from yandex_cloud_ml_sdk._assistants.utils import get_completion_options, get_prompt_trunctation_options -from yandex_cloud_ml_sdk._threads.thread import AsyncThread, BaseThread, Thread, ThreadTypeT +from yandex_cloud_ml_sdk._threads.thread import BaseThread from yandex_cloud_ml_sdk._types.domain import BaseDomain from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator @@ -19,15 +19,13 @@ from .run import AsyncRun, Run, RunTypeT -class BaseRuns(BaseDomain, Generic[RunTypeT, AssistantTypeT, ThreadTypeT]): +class BaseRuns(BaseDomain, Generic[RunTypeT]): _run_impl: type[RunTypeT] - _assistant_impl: type[AssistantTypeT] - _thread_impl: type[ThreadTypeT] async def _create( self, - assistant: str | AssistantTypeT, - thread: str | ThreadTypeT, + assistant: str | BaseAssistant, + thread: str | BaseThread, *, stream: bool, custom_temperature: UndefinedOr[float] = UNDEFINED, @@ -96,7 +94,7 @@ async def _get( async def _get_last_by_thread( self, - thread: str | ThreadTypeT, + thread: str | BaseThread, *, timeout: float = 60 ) -> RunTypeT: @@ -153,23 +151,86 @@ async def _list( page_token_ = response.next_page_token -class AsyncRuns(BaseRuns[AsyncRun, AsyncAssistant, AsyncThread]): +class AsyncRuns(BaseRuns[AsyncRun]): + # NB: there is no public 'create' _run_impl = AsyncRun - _assistant_impl = AsyncAssistant - _thread_impl = AsyncThread - # NB: there is no public 'create' - get = BaseRuns._get - get_last_by_thread = BaseRuns._get_last_by_thread - list = BaseRuns._list + async def get( + self, + run_id: str, + *, + timeout: float = 60, + ) -> AsyncRun: + return await self._get( + run_id=run_id, + timeout=timeout, + ) + + async def get_last_by_thread( + self, + thread: str | BaseThread, + *, + timeout: float = 60 + ) -> AsyncRun: + return await self._get_last_by_thread( + thread=thread, + timeout=timeout, + ) + + async def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AsyncRun]: + async for run in self._list( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ): + yield run -class Runs(BaseRuns[Run, Assistant, Thread]): +class Runs(BaseRuns[Run]): _run_impl = Run - _assistant_impl = Assistant - _thread_impl = Thread # NB: there is no public 'create' - get = run_sync(BaseRuns._get) - get_last_by_thread = run_sync(BaseRuns._get_last_by_thread) - list = run_sync_generator(BaseRuns._list) + __get = run_sync(BaseRuns._get) + __get_last_by_thread = run_sync(BaseRuns._get_last_by_thread) + __list = run_sync_generator(BaseRuns._list) + + def get( + self, + run_id: str, + *, + timeout: float = 60, + ) -> Run: + return self.__get( + run_id=run_id, + timeout=timeout, + ) + + def get_last_by_thread( + self, + thread: str | BaseThread, + *, + timeout: float = 60 + ) -> Run: + return self.__get_last_by_thread( + thread=thread, + timeout=timeout, + ) + + def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[Run]: + yield from self.__list( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ) diff --git a/src/yandex_cloud_ml_sdk/_runs/run.py b/src/yandex_cloud_ml_sdk/_runs/run.py index 5b08ff5..cfa1c3a 100644 --- a/src/yandex_cloud_ml_sdk/_runs/run.py +++ b/src/yandex_cloud_ml_sdk/_runs/run.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar +from typing import TYPE_CHECKING, Any, AsyncIterator, Iterator, TypeVar from google.protobuf.wrappers_pb2 import Int64Value from yandex.cloud.ai.assistants.v1.runs.run_pb2 import Run as ProtoRun @@ -49,7 +49,7 @@ def _kwargs_from_message(cls, proto: ProtoRun, sdk: BaseSDK) -> dict[str, Any]: return kwargs - async def _get_run(self, *, timeout=60) -> ProtoRun: + async def _get_run(self, *, timeout: float = 60) -> ProtoRun: request = GetRunRequest(run_id=self.id) async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: @@ -62,12 +62,12 @@ async def _get_run(self, *, timeout=60) -> ProtoRun: return response - async def _get_status(self, *, timeout=60) -> RunStatus: # type: ignore[override] + async def _get_status(self, *, timeout: float = 60) -> RunStatus: # type: ignore[override] run = await self._get_run(timeout=timeout) return RunStatus._from_proto(proto=run.state.status) - async def _get_result(self, *, timeout=60) -> RunResult: + async def _get_result(self, *, timeout: float = 60) -> RunResult: run = await self._get_run(timeout=timeout) return RunResult._from_proto(sdk=self._sdk, proto=run) @@ -76,7 +76,7 @@ async def _listen( self, *, events_start_idx: int = 0, - timeout=60, + timeout: float = 60, ) -> AsyncIterator[RunStreamEvent]: request = ListenRunRequest( run_id=self.id, @@ -96,22 +96,79 @@ async def _listen( class AsyncRun(BaseRun): - get_status = BaseRun._get_status - get_result = BaseRun._get_result - wait = BaseRun._wait - listen = BaseRun._listen - __aiter__ = BaseRun._listen + async def get_status(self, *, timeout: float = 60) -> RunStatus: + return await self._get_status(timeout=timeout) + + async def get_result(self, *, timeout: float = 60) -> RunResult: + return await self._get_result(timeout=timeout) + + async def listen( + self, + *, + events_start_idx: int = 0, + timeout: float = 60, + ) -> AsyncIterator[RunStreamEvent]: + async for event in self._listen( + events_start_idx=events_start_idx, + timeout=timeout, + ): + yield event + + __aiter__ = listen + + async def wait( + self, + *, + timeout: float = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> RunResult: + return await self._wait( + timeout=timeout, + poll_timeout=poll_timeout, + poll_interval=poll_interval, + ) def __await__(self): return self.wait().__await__() class Run(BaseRun): - get_status = run_sync(BaseRun._get_status) - get_result = run_sync(BaseRun._get_result) - wait = run_sync(BaseRun._wait) - listen = run_sync_generator(BaseRun._listen) - __iter__ = run_sync_generator(BaseRun._listen) + __get_status = run_sync(BaseRun._get_status) + __get_result = run_sync(BaseRun._get_result) + __wait = run_sync(BaseRun._wait) + __listen = run_sync_generator(BaseRun._listen) + __iter__ = __listen + def get_status(self, *, timeout: float = 60) -> RunStatus: + return self.__get_status(timeout=timeout) + + def get_result(self, *, timeout: float = 60) -> RunResult: + return self.__get_result(timeout=timeout) + + def listen( + self, + *, + events_start_idx: int = 0, + timeout: float = 60, + ) -> Iterator[RunStreamEvent]: + yield from self.__listen( + events_start_idx=events_start_idx, + timeout=timeout, + ) + + def wait( + self, + *, + timeout: float = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> RunResult: + # NB: mypy can't unterstand normally __wait return type and thinks its ResultTypeT + return self.__wait( # type: ignore[return-value] + timeout=timeout, + poll_timeout=poll_timeout, + poll_interval=poll_interval, + ) RunTypeT = TypeVar('RunTypeT', bound=BaseRun) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py index 764c76b..34233e2 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic +from typing import AsyncIterator, Generic, Iterator from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import SearchIndex as ProtoSearchIndex from yandex.cloud.ai.assistants.v1.searchindex.search_index_pb2 import TextSearchIndex, VectorSearchIndex @@ -138,15 +138,106 @@ class AsyncSearchIndexes(BaseSearchIndexes[AsyncSearchIndex, AsyncOperation[Asyn _impl = AsyncSearchIndex _operation_type = AsyncOperation - get = BaseSearchIndexes._get - create_deferred = BaseSearchIndexes._create_deferred - list = BaseSearchIndexes._list + async def create_deferred( + self, + files: ResourceType[BaseFile], + *, + index_type: UndefinedOr[BaseSearchIndexType] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncOperation[AsyncSearchIndex]: + return await self._create_deferred( + files=files, + index_type=index_type, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + async def get( + self, + search_index_id: str, + *, + timeout: float = 60, + ) -> AsyncSearchIndex: + return await self._get( + search_index_id=search_index_id, + timeout=timeout, + ) + + async def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AsyncSearchIndex]: + async for search_index in self._list( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ): + yield search_index -class SearchIndexes(BaseSearchIndexes[SearchIndex, Operation[AsyncSearchIndex]]): +class SearchIndexes(BaseSearchIndexes[SearchIndex, Operation[SearchIndex]]): _impl = SearchIndex _operation_type = Operation - get = run_sync(BaseSearchIndexes._get) - create_deferred = run_sync(BaseSearchIndexes._create_deferred) - list = run_sync_generator(BaseSearchIndexes._list) + __get = run_sync(BaseSearchIndexes._get) + __create_deferred = run_sync(BaseSearchIndexes._create_deferred) + __list = run_sync_generator(BaseSearchIndexes._list) + + def create_deferred( + self, + files: ResourceType[BaseFile], + *, + index_type: UndefinedOr[BaseSearchIndexType] = UNDEFINED, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Operation[SearchIndex]: + return self.__create_deferred( + files=files, + index_type=index_type, + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + def get( + self, + search_index_id: str, + *, + timeout: float = 60, + ) -> SearchIndex: + return self.__get( + search_index_id=search_index_id, + timeout=timeout, + ) + + def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[SearchIndex]: + yield from self.__list( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py index 3e48460..93340a6 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import TYPE_CHECKING, Any, AsyncIterator, TypeVar +from typing import TYPE_CHECKING, Any, AsyncIterator, Iterator, TypeVar from typing_extensions import Self from yandex.cloud.ai.assistants.v1.searchindex.search_index_file_pb2 import SearchIndexFile as ProtoSearchIndexFile @@ -178,17 +178,113 @@ class RichSearchIndex(BaseSearchIndex): class AsyncSearchIndex(RichSearchIndex): - update = RichSearchIndex._update - delete = RichSearchIndex._delete - get_file = RichSearchIndex._get_file - list_files = RichSearchIndex._list_files + async def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return await self._update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + async def delete( + self, + *, + timeout: float = 60, + ) -> None: + await self._delete(timeout=timeout) + + async def get_file( + self, + file_id: str, + *, + timeout: float = 60 + ) -> SearchIndexFile: + return await self._get_file( + file_id=file_id, + timeout=timeout + ) + + async def list_files( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[SearchIndexFile]: + async for file in self._list_files( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ): + yield file class SearchIndex(RichSearchIndex): - update = run_sync(RichSearchIndex._update) - delete = run_sync(RichSearchIndex._delete) - get_file = run_sync(RichSearchIndex._get_file) - list_files = run_sync_generator(RichSearchIndex._list_files) + __update = run_sync(RichSearchIndex._update) + __delete = run_sync(RichSearchIndex._delete) + __get_file = run_sync(RichSearchIndex._get_file) + __list_files = run_sync_generator(RichSearchIndex._list_files) + + def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return self.__update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout + ) + + def delete( + self, + *, + timeout: float = 60, + ) -> None: + self.__delete(timeout=timeout) + + def get_file( + self, + file_id: str, + *, + timeout: float = 60 + ) -> SearchIndexFile: + return self.__get_file( + file_id=file_id, + timeout=timeout + ) + + def list_files( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[SearchIndexFile]: + yield from self.__list_files( + page_size=page_size, + page_token=page_token, + timeout=timeout, + ) SearchIndexTypeT = TypeVar('SearchIndexTypeT', bound=BaseSearchIndex) diff --git a/src/yandex_cloud_ml_sdk/_threads/domain.py b/src/yandex_cloud_ml_sdk/_threads/domain.py index 75558e3..9e6c681 100644 --- a/src/yandex_cloud_ml_sdk/_threads/domain.py +++ b/src/yandex_cloud_ml_sdk/_threads/domain.py @@ -1,7 +1,7 @@ # pylint: disable=protected-access,no-name-in-module from __future__ import annotations -from typing import AsyncIterator, Generic +from typing import AsyncIterator, Generic, Iterator from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread from yandex.cloud.ai.assistants.v1.threads.thread_service_pb2 import ( @@ -109,14 +109,97 @@ async def _list( class AsyncThreads(BaseThreads[AsyncThread]): _thread_impl = AsyncThread - get = BaseThreads._get - create = BaseThreads._create - list = BaseThreads._list + async def create( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> AsyncThread: + return await self._create( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + async def get( + self, + thread_id: str, + *, + timeout: float = 60, + ) -> AsyncThread: + return await self._get( + thread_id=thread_id, + timeout=timeout, + ) + + async def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> AsyncIterator[AsyncThread]: + async for thread in self._list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ): + yield thread class Threads(BaseThreads[Thread]): _thread_impl = Thread - get = run_sync(BaseThreads._get) - create = run_sync(BaseThreads._create) - list = run_sync_generator(BaseThreads._list) + __get = run_sync(BaseThreads._get) + __create = run_sync(BaseThreads._create) + __list = run_sync_generator(BaseThreads._list) + + def create( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Thread: + return self.__create( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + def get( + self, + thread_id: str, + *, + timeout: float = 60, + ) -> Thread: + return self.__get( + thread_id=thread_id, + timeout=timeout, + ) + + def list( + self, + *, + page_size: UndefinedOr[int] = UNDEFINED, + page_token: UndefinedOr[str] = UNDEFINED, + timeout: float = 60 + ) -> Iterator[Thread]: + yield from self.__list( + page_size=page_size, + page_token=page_token, + timeout=timeout + ) diff --git a/src/yandex_cloud_ml_sdk/_threads/thread.py b/src/yandex_cloud_ml_sdk/_threads/thread.py index cfed46c..ba74adc 100644 --- a/src/yandex_cloud_ml_sdk/_threads/thread.py +++ b/src/yandex_cloud_ml_sdk/_threads/thread.py @@ -3,7 +3,7 @@ import dataclasses from datetime import datetime -from typing import AsyncIterator, TypeVar +from typing import AsyncIterator, Iterator, TypeVar from typing_extensions import Self from yandex.cloud.ai.assistants.v1.threads.thread_pb2 import Thread as ProtoThread @@ -135,19 +135,109 @@ class RichThread(BaseThread): class AsyncThread(RichThread): - update = RichThread._update - delete = RichThread._delete - write = RichThread._write - read = RichThread._read - __aiter__ = RichThread._read + async def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return await self._update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + async def delete( + self, + *, + timeout: float = 60, + ) -> None: + await self._delete(timeout=timeout) + + async def write( + self, + content: str, + *, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + return await self._write( + content=content, + labels=labels, + timeout=timeout + ) + + async def read( + self, + *, + timeout: float = 60, + ) -> AsyncIterator[Message]: + async for message in self._read(timeout=timeout): + yield message + + __aiter__ = read class Thread(RichThread): - update = run_sync(RichThread._update) - delete = run_sync(RichThread._delete) - write = run_sync(RichThread._write) - read = run_sync_generator(RichThread._read) - __iter__ = run_sync_generator(RichThread._read) + __update = run_sync(RichThread._update) + __delete = run_sync(RichThread._delete) + __write = run_sync(RichThread._write) + __read = run_sync_generator(RichThread._read) + + def update( + self, + *, + name: UndefinedOr[str] = UNDEFINED, + description: UndefinedOr[str] = UNDEFINED, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + ttl_days: UndefinedOr[int] = UNDEFINED, + expiration_policy: UndefinedOr[ExpirationPolicyAlias] = UNDEFINED, + timeout: float = 60, + ) -> Self: + return self.__update( + name=name, + description=description, + labels=labels, + ttl_days=ttl_days, + expiration_policy=expiration_policy, + timeout=timeout, + ) + + def delete( + self, + *, + timeout: float = 60, + ) -> None: + self.__delete(timeout=timeout) + + def write( + self, + content: str, + *, + labels: UndefinedOr[dict[str, str]] = UNDEFINED, + timeout: float = 60, + ) -> Message: + return self.__write( + content=content, + labels=labels, + timeout=timeout + ) + + def read( + self, + *, + timeout: float = 60, + ) -> Iterator[Message]: + yield from self.__read(timeout=timeout) + + __iter__ = read ThreadTypeT = TypeVar('ThreadTypeT', bound=BaseThread) diff --git a/src/yandex_cloud_ml_sdk/_types/operation.py b/src/yandex_cloud_ml_sdk/_types/operation.py index a01b535..706124d 100644 --- a/src/yandex_cloud_ml_sdk/_types/operation.py +++ b/src/yandex_cloud_ml_sdk/_types/operation.py @@ -49,11 +49,11 @@ class OperationInterface(abc.ABC, Generic[ResultTypeT]): id: str @abc.abstractmethod - async def _get_status(self, *, timeout=60) -> OperationStatus: + async def _get_status(self, *, timeout: float = 60) -> OperationStatus: pass @abc.abstractmethod - async def _get_result(self, *, timeout=60) -> ResultTypeT: + async def _get_result(self, *, timeout: float = 60) -> ResultTypeT: pass async def _wait_impl(self, timeout, poll_interval) -> OperationStatus: @@ -67,7 +67,7 @@ async def _wait_impl(self, timeout, poll_interval) -> OperationStatus: async def _wait( self, *, - timeout: int = 60, + timeout: float = 60, poll_timeout: int = 3600, poll_interval: float = 10, ) -> ResultTypeT: @@ -97,7 +97,7 @@ def id(self): def _client(self): return self._sdk._client - async def _get_status(self, *, timeout=60) -> OperationStatus: + async def _get_status(self, *, timeout: float = 60) -> OperationStatus: request = GetOperationRequest(operation_id=self.id) async with self._client.get_service_stub(OperationServiceStub, timeout=timeout) as stub: response = await self._client.call_service( @@ -113,7 +113,7 @@ async def _get_status(self, *, timeout=60) -> OperationStatus: ) return status - async def _get_result(self, *, timeout=60) -> ResultTypeT: + async def _get_result(self, *, timeout: float = 60) -> ResultTypeT: status = self._last_known_status if status is None: status = await self._get_status(timeout=timeout) @@ -140,7 +140,7 @@ async def _get_result(self, *, timeout=60) -> ResultTypeT: f"operation {self.id} is done but response have result neither error fields set" ) - async def _cancel(self, *, timeout=60) -> OperationStatus: + async def _cancel(self, *, timeout: float = 60) -> OperationStatus: request = CancelOperationRequest(operation_id=self.id) async with self._client.get_service_stub(OperationServiceStub, timeout=timeout) as stub: response = await self._client.call_service( @@ -159,7 +159,7 @@ async def _cancel(self, *, timeout=60) -> OperationStatus: async def _wait( self, *, - timeout: int = 60, + timeout: float = 60, poll_timeout: int = 3600, poll_interval: float = 10, ) -> ResultTypeT: @@ -173,17 +173,59 @@ async def _wait( class AsyncOperation(BaseOperation[ResultTypeT]): - get_status = BaseOperation._get_status - get_result = BaseOperation._get_result - wait = BaseOperation._wait - cancel = BaseOperation._cancel + async def get_status(self, *, timeout: float = 60) -> OperationStatus: + return await self._get_status(timeout=timeout) + + async def get_result(self, *, timeout: float = 60) -> ResultTypeT: + return await self._get_result(timeout=timeout) + + async def cancel(self, *, timeout: float = 60) -> None: + await self._cancel(timeout=timeout) + + async def wait( + self, + *, + timeout: float = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> ResultTypeT: + return await self._wait( + timeout=timeout, + poll_timeout=poll_timeout, + poll_interval=poll_interval, + ) + + def __await__(self): + return self.wait().__await__() class Operation(BaseOperation[ResultTypeT]): - get_status = run_sync(BaseOperation._get_status) - get_result = run_sync(BaseOperation._get_result) - wait = run_sync(BaseOperation._wait) - cancel = run_sync(BaseOperation._cancel) + __get_status = run_sync(BaseOperation._get_status) + __get_result = run_sync(BaseOperation._get_result) + __wait = run_sync(BaseOperation._wait) + __cancel = run_sync(BaseOperation._cancel) + + def get_status(self, *, timeout: float = 60) -> OperationStatus: + return self.__get_status(timeout=timeout) + + def get_result(self, *, timeout: float = 60) -> ResultTypeT: + return self.__get_result(timeout=timeout) + + def cancel(self, *, timeout: float = 60) -> None: + self.__cancel(timeout=timeout) + + def wait( + self, + *, + timeout: float = 60, + poll_timeout: int = 3600, + poll_interval: float = 10, + ) -> ResultTypeT: + return self.__wait( + timeout=timeout, + poll_timeout=poll_timeout, + poll_interval=poll_interval, + ) OperationTypeT = TypeVar('OperationTypeT', bound=BaseOperation) From dc448283f08241b75e2dad3369644af40fff532e Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 1 Nov 2024 14:29:11 +0100 Subject: [PATCH 10/13] Remove page_token parameter (#12) --- src/yandex_cloud_ml_sdk/_assistants/domain.py | 7 +------ src/yandex_cloud_ml_sdk/_files/domain.py | 7 +------ src/yandex_cloud_ml_sdk/_runs/domain.py | 7 +------ src/yandex_cloud_ml_sdk/_search_indexes/domain.py | 7 +------ src/yandex_cloud_ml_sdk/_search_indexes/search_index.py | 7 +------ src/yandex_cloud_ml_sdk/_threads/domain.py | 7 +------ 6 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/yandex_cloud_ml_sdk/_assistants/domain.py b/src/yandex_cloud_ml_sdk/_assistants/domain.py index d473810..bbc692a 100644 --- a/src/yandex_cloud_ml_sdk/_assistants/domain.py +++ b/src/yandex_cloud_ml_sdk/_assistants/domain.py @@ -119,10 +119,9 @@ async def _list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AssistantTypeT]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(AssistantServiceStub, timeout=timeout) as stub: @@ -198,12 +197,10 @@ async def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AsyncAssistant]: async for assistant in self._list( page_size=page_size, - page_token=page_token, timeout=timeout ): yield assistant @@ -263,11 +260,9 @@ def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[Assistant]: yield from self.__list( page_size=page_size, - page_token=page_token, timeout=timeout ) diff --git a/src/yandex_cloud_ml_sdk/_files/domain.py b/src/yandex_cloud_ml_sdk/_files/domain.py index 2596595..4a27a04 100644 --- a/src/yandex_cloud_ml_sdk/_files/domain.py +++ b/src/yandex_cloud_ml_sdk/_files/domain.py @@ -105,10 +105,9 @@ async def _list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[FileTypeT]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(FileServiceStub, timeout=timeout) as stub: @@ -198,12 +197,10 @@ async def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AsyncFile]: async for file in self._list( page_size=page_size, - page_token=page_token, timeout=timeout ): yield file @@ -278,11 +275,9 @@ def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[File]: yield from self.__list( page_size=page_size, - page_token=page_token, timeout=timeout ) diff --git a/src/yandex_cloud_ml_sdk/_runs/domain.py b/src/yandex_cloud_ml_sdk/_runs/domain.py index fb30c42..3760427 100644 --- a/src/yandex_cloud_ml_sdk/_runs/domain.py +++ b/src/yandex_cloud_ml_sdk/_runs/domain.py @@ -122,10 +122,9 @@ async def _list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[RunTypeT]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(RunServiceStub, timeout=timeout) as stub: @@ -181,12 +180,10 @@ async def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AsyncRun]: async for run in self._list( page_size=page_size, - page_token=page_token, timeout=timeout, ): yield run @@ -226,11 +223,9 @@ def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[Run]: yield from self.__list( page_size=page_size, - page_token=page_token, timeout=timeout, ) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py index 34233e2..967bfd9 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py @@ -105,10 +105,9 @@ async def _list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[SearchIndexTypeT]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: @@ -176,12 +175,10 @@ async def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AsyncSearchIndex]: async for search_index in self._list( page_size=page_size, - page_token=page_token, timeout=timeout, ): yield search_index @@ -233,11 +230,9 @@ def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[SearchIndex]: yield from self.__list( page_size=page_size, - page_token=page_token, timeout=timeout, ) diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py index 93340a6..20f5533 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/search_index.py @@ -134,10 +134,9 @@ async def _list_files( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[SearchIndexFile]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(SearchIndexFileServiceStub, timeout=timeout) as stub: @@ -219,12 +218,10 @@ async def list_files( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[SearchIndexFile]: async for file in self._list_files( page_size=page_size, - page_token=page_token, timeout=timeout, ): yield file @@ -277,12 +274,10 @@ def list_files( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[SearchIndexFile]: yield from self.__list_files( page_size=page_size, - page_token=page_token, timeout=timeout, ) diff --git a/src/yandex_cloud_ml_sdk/_threads/domain.py b/src/yandex_cloud_ml_sdk/_threads/domain.py index 9e6c681..69503bf 100644 --- a/src/yandex_cloud_ml_sdk/_threads/domain.py +++ b/src/yandex_cloud_ml_sdk/_threads/domain.py @@ -77,10 +77,9 @@ async def _list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[ThreadTypeT]: - page_token_ = get_defined_value(page_token, '') + page_token_ = '' page_size_ = get_defined_value(page_size, 0) async with self._client.get_service_stub(ThreadServiceStub, timeout=timeout) as stub: @@ -143,12 +142,10 @@ async def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> AsyncIterator[AsyncThread]: async for thread in self._list( page_size=page_size, - page_token=page_token, timeout=timeout ): yield thread @@ -195,11 +192,9 @@ def list( self, *, page_size: UndefinedOr[int] = UNDEFINED, - page_token: UndefinedOr[str] = UNDEFINED, timeout: float = 60 ) -> Iterator[Thread]: yield from self.__list( page_size=page_size, - page_token=page_token, timeout=timeout ) From 80dc385a20a8e87edb6ce20c48468df283895e75 Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 1 Nov 2024 15:44:20 +0100 Subject: [PATCH 11/13] Imrove assistant examples, make sync version (#13) --- .../assistants/assistant_with_search_index.py | 2 +- examples/async/assistants/assistants.py | 11 +- examples/async/assistants/files.py | 15 +- examples/async/assistants/runs.py | 20 ++- examples/async/assistants/search_indexes.py | 20 ++- examples/async/assistants/threads.py | 18 +- examples/sync/assistants/__init__.py | 0 .../assistants/assistant_with_search_index.py | 60 +++++++ examples/sync/assistants/assistants.py | 42 +++++ examples/sync/assistants/example_file | 1 + examples/sync/assistants/files.py | 38 ++++ examples/sync/assistants/maldives_example.txt | 1 + examples/sync/assistants/runs.py | 60 +++++++ examples/sync/assistants/search_indexes.py | 67 +++++++ examples/sync/assistants/search_query.txt | 1 + examples/sync/assistants/threads.py | 39 ++++ examples/sync/assistants/turkey_example.txt | 170 ++++++++++++++++++ 17 files changed, 532 insertions(+), 33 deletions(-) create mode 100644 examples/sync/assistants/__init__.py create mode 100755 examples/sync/assistants/assistant_with_search_index.py create mode 100755 examples/sync/assistants/assistants.py create mode 100644 examples/sync/assistants/example_file create mode 100755 examples/sync/assistants/files.py create mode 100644 examples/sync/assistants/maldives_example.txt create mode 100755 examples/sync/assistants/runs.py create mode 100755 examples/sync/assistants/search_indexes.py create mode 100644 examples/sync/assistants/search_query.txt create mode 100755 examples/sync/assistants/threads.py create mode 100644 examples/sync/assistants/turkey_example.txt diff --git a/examples/async/assistants/assistant_with_search_index.py b/examples/async/assistants/assistant_with_search_index.py index d598a2f..99a3c5d 100755 --- a/examples/async/assistants/assistant_with_search_index.py +++ b/examples/async/assistants/assistant_with_search_index.py @@ -33,7 +33,7 @@ async def main() -> None: files = await asyncio.gather(*file_coros) operation = await sdk.search_indexes.create_deferred(files) - search_index = await operation.wait() + search_index = await operation tool = sdk.tools.search_index(search_index) diff --git a/examples/async/assistants/assistants.py b/examples/async/assistants/assistants.py index 2638162..5617195 100755 --- a/examples/async/assistants/assistants.py +++ b/examples/async/assistants/assistants.py @@ -22,16 +22,19 @@ async def main() -> None: temperature=0.5, max_prompt_tokens=50, ) + print(f"{assistant=}") + assistant2 = await sdk.assistants.get(assistant.id) - print(assistant2) + print(f"same {assistant2=}") + await assistant2.update(model='yandexgpt-lite', name='foo', max_tokens=5) - print(assistant2) + print(f"updated {assistant2=}") async for version in assistant.list_versions(): - print(version) + print(f"assistant {version=}") async for assistant in sdk.assistants.list(): - print(f"deliting assistant {assistant}") + print(f"deleting {assistant=}") await assistant.delete() diff --git a/examples/async/assistants/files.py b/examples/async/assistants/files.py index a48ed93..2c8dce0 100755 --- a/examples/async/assistants/files.py +++ b/examples/async/assistants/files.py @@ -18,22 +18,21 @@ async def main() -> None: path = pathlib.Path(__file__).parent / 'example_file' file = await sdk.files.upload(path, ttl_days=5, expiration_policy="static") - - print(file) + print(f"created {file=}") await file.update(name='foo', ttl_days=9) - print(file) + print(f"updated {file=}") second = await sdk.files.get(file.id) + print(f"just as file {second=}") await second.update(name='foo', expiration_policy='since_last_active') + print(f"it keeps update from first instance, {second=}") - print(second) - - print(await file.get_url()) - print(await file.download_as_bytes()) + print(f"url for downloading: {await file.get_url()=}") + print(f"getting content {await file.download_as_bytes()=}") async for file in sdk.files.list(): - print(f"delete file {file}") + print(f"deleting {file=}") await file.delete() if __name__ == '__main__': diff --git a/examples/async/assistants/runs.py b/examples/async/assistants/runs.py index 6dabffb..9832581 100755 --- a/examples/async/assistants/runs.py +++ b/examples/async/assistants/runs.py @@ -22,34 +22,40 @@ async def main() -> None: ttl_days=6, expiration_policy='static', ) - print('assistant: ', assistant) + print(f'new {assistant=}') thread = await sdk.threads.create( name='foo', ttl_days=6, expiration_policy='static', ) - print('thread: ', thread) + message = await thread.write("hi! how are you") + print(f'new {thread=} with {message=}') - await thread.write("hi! how are you") run = await assistant.run_stream(thread) + print(f'new stream {run=} on this thread and assistant') async for event in run: - print('event:', event) + print(f'from stream {event=}') + + message = await thread.write("how is your name?") + print(f'second {message=}') - await thread.write("how is your name?") run = await assistant.run(thread) + print(f'second {run=}') result = await run - print('run result:', result) + print(f'run {result=}') run = await sdk.runs.get_last_by_thread(thread) - print('last run:', run) + print(f'last run in thread, same as last one: {run}') + # NB: it doesn't work at the moment at the backend # async for run in sdk.runs.list(page_size=10): # print('run:', run) async for assistant in sdk.assistants.list(): await assistant.delete() + await thread.delete() if __name__ == '__main__': diff --git a/examples/async/assistants/search_indexes.py b/examples/async/assistants/search_indexes.py index 8cd54cd..6dbf0a1 100755 --- a/examples/async/assistants/search_indexes.py +++ b/examples/async/assistants/search_indexes.py @@ -43,19 +43,25 @@ async def main() -> None: ) ) search_index = await operation.wait() - print(f"search index {search_index}") + print(f"new {search_index=}") - index_files = [file async for file in search_index.list_files()] - print(f"search index files: {index_files}") - index_file = await search_index.get_file(index_files[0].id) - print(f"search index file: {index_file}") + search_index2 = await sdk.search_indexes.get(search_index.id) + print(f"same as first, {search_index2=}") + + await search_index.update(name="foo") + print(f"now with a name {search_index=}") + + # NB: it doesn't work at the moment + # index_files = [file async for file in search_index.list_files()] + # print(f"search index files: {index_files}") + # index_file = await search_index.get_file(index_files[0].id) + # print(f"search index file: {index_file}") for file in files: - print(f"delete file {file}") await file.delete() async for search_index in sdk.search_indexes.list(): - print(f"delete search_index {search_index}") + print(f"delete {search_index=}") await search_index.delete() diff --git a/examples/async/assistants/threads.py b/examples/async/assistants/threads.py index 3f57482..e5cbed1 100755 --- a/examples/async/assistants/threads.py +++ b/examples/async/assistants/threads.py @@ -16,18 +16,24 @@ async def main() -> None: ) thread = await sdk.threads.create(name='foo', ttl_days=5, expiration_policy="static") - print(thread) + print(f"new {thread=}") + second = await sdk.threads.get(thread.id) + print(f"same as first, {second=}") await second.update(ttl_days=9) - print(second) + print(f"with updated epiration config, {second=}") + + message = await thread.write("content") + message2 = await second.write("content2") + print(f"hey, we just writed {message=} and {message2} into the thread") - await thread.write("content") - await second.write("content2") + print("and now we could read it:") async for message in thread: - print(message) - print(message.text) + print(f" {message=}") + print(f" {message.text=}\n") async for thread in sdk.threads.list(): + print(f"deleting thread {thread=}") await thread.delete() diff --git a/examples/sync/assistants/__init__.py b/examples/sync/assistants/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/sync/assistants/assistant_with_search_index.py b/examples/sync/assistants/assistant_with_search_index.py new file mode 100755 index 0000000..8daf80e --- /dev/null +++ b/examples/sync/assistants/assistant_with_search_index.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import pathlib + +from yandex_cloud_ml_sdk import YCloudML + + +def local_path(path: str) -> pathlib.Path: + return pathlib.Path(__file__).parent / path + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'ai-files': 'assistant.api.cloud.yandex.net', + 'operation': 'assistant.api.cloud.yandex.net', + } + ) + + files = [] + for path in ['turkey_example.txt', 'maldives_example.txt']: + file = sdk.files.upload( + local_path(path), + ttl_days=5, + expiration_policy="static", + ) + files.append(file) + + operation = sdk.search_indexes.create_deferred(files) + search_index = operation.wait() + + tool = sdk.tools.search_index(search_index) + + assistant = sdk.assistants.create('yandexgpt', tools=[tool]) + thread = sdk.threads.create() + + for search_query in ( + local_path('search_query.txt').read_text().splitlines()[0], + "Cколько пошлина в Анталье" + ): + thread.write(search_query) + run = assistant.run(thread) + result = run.wait() + print('Question', search_query) + print('Answer:', result.text) + + search_index.delete() + thread.delete() + assistant.delete() + + for file in files: + file.delete() + + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/assistants.py b/examples/sync/assistants/assistants.py new file mode 100755 index 0000000..46a0e25 --- /dev/null +++ b/examples/sync/assistants/assistants.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +from yandex_cloud_ml_sdk import YCloudML + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + assistant = sdk.assistants.create( + 'yandexgpt', + ttl_days=1, + expiration_policy='static', + temperature=0.5, + max_prompt_tokens=50, + ) + print(f"{assistant=}") + + assistant2 = sdk.assistants.get(assistant.id) + print(f"same {assistant2=}") + + assistant2.update(model='yandexgpt-lite', name='foo', max_tokens=5) + print(f"updated {assistant2=}") + + for version in assistant.list_versions(): + print(f"assistant {version=}") + + for assistant in sdk.assistants.list(): + print(f"deleting {assistant=}") + + assistant.delete() + + + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/example_file b/examples/sync/assistants/example_file new file mode 100644 index 0000000..2580a08 --- /dev/null +++ b/examples/sync/assistants/example_file @@ -0,0 +1 @@ +Some example diff --git a/examples/sync/assistants/files.py b/examples/sync/assistants/files.py new file mode 100755 index 0000000..704638e --- /dev/null +++ b/examples/sync/assistants/files.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import pathlib + +from yandex_cloud_ml_sdk import YCloudML + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-files': 'assistant.api.cloud.yandex.net' + } + ) + + path = pathlib.Path(__file__).parent / 'example_file' + file = sdk.files.upload(path, ttl_days=5, expiration_policy="static") + print(f"created {file=}") + + file.update(name='foo', ttl_days=9) + print(f"updated {file=}") + + second = sdk.files.get(file.id) + print(f"just as file {second=}") + second.update(name='foo', expiration_policy='since_last_active') + print(f"it keeps update from first instance, {second=}") + + print(f"url for downloading: {file.get_url()=}") + print(f"getting content {file.download_as_bytes()=}") + + for file in sdk.files.list(): + print(f"deleting {file=}") + file.delete() + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/maldives_example.txt b/examples/sync/assistants/maldives_example.txt new file mode 100644 index 0000000..71029a7 --- /dev/null +++ b/examples/sync/assistants/maldives_example.txt @@ -0,0 +1 @@ +Стоимость въезда/выезда с Мальдив - 10 тысяч долларов в обе стороны diff --git a/examples/sync/assistants/runs.py b/examples/sync/assistants/runs.py new file mode 100755 index 0000000..1bea6fa --- /dev/null +++ b/examples/sync/assistants/runs.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +from yandex_cloud_ml_sdk import YCloudML + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + assistant = sdk.assistants.create( + 'yandexgpt', + temperature=0.5, + max_prompt_tokens=50, + ttl_days=6, + expiration_policy='static', + ) + print(f'new {assistant=}') + + thread = sdk.threads.create( + name='foo', + ttl_days=6, + expiration_policy='static', + ) + message = thread.write("hi! how are you") + print(f'new {thread=} with {message=}') + + run = assistant.run_stream(thread) + print(f'new stream {run=} on this thread and assistant') + for event in run: + print(f'from stream {event=}') + + message = thread.write("how is your name?") + print(f'second {message=}') + + run = assistant.run(thread) + print(f'second {run=}') + result = run.wait() + print(f'run {result=}') + + run = sdk.runs.get_last_by_thread(thread) + print(f'last run in thread, same as last one: {run}') + + # NB: it doesn't work at the moment at the backend + # for run in sdk.runs.list(page_size=10): + # print('run:', run) + + for assistant in sdk.assistants.list(): + assistant.delete() + + thread.delete() + + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/search_indexes.py b/examples/sync/assistants/search_indexes.py new file mode 100755 index 0000000..1b4741a --- /dev/null +++ b/examples/sync/assistants/search_indexes.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import pathlib + +from yandex_cloud_ml_sdk import YCloudML +from yandex_cloud_ml_sdk.search_indexes import StaticIndexChunkingStrategy, TextSearchIndexType + + +def local_path(path: str) -> pathlib.Path: + return pathlib.Path(__file__).parent / path + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-files': 'assistant.api.cloud.yandex.net', + 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'operation': 'assistant.api.cloud.yandex.net', + } + ) + + files = [] + for path in ['turkey_example.txt', 'maldives_example.txt']: + file = sdk.files.upload( + local_path(path), + ttl_days=5, + expiration_policy="static", + ) + files.append(file) + + operation = sdk.search_indexes.create_deferred( + files, + index_type=TextSearchIndexType( + chunking_strategy=StaticIndexChunkingStrategy( + max_chunk_size_tokens=700, + chunk_overlap_tokens=300, + ) + ) + ) + search_index = operation.wait() + print(f"new {search_index=}") + + search_index2 = sdk.search_indexes.get(search_index.id) + print(f"same as first, {search_index2=}") + + search_index.update(name="foo") + print(f"now with a name {search_index=}") + + # NB: it doesn't work at the moment + # index_files = [file for file in search_index.list_files()] + # print(f"search index files: {index_files}") + # index_file = search_index.get_file(index_files[0].id) + # print(f"search index file: {index_file}") + + for file in files: + file.delete() + + for search_index in sdk.search_indexes.list(): + print(f"delete {search_index=}") + search_index.delete() + + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/search_query.txt b/examples/sync/assistants/search_query.txt new file mode 100644 index 0000000..a9126d1 --- /dev/null +++ b/examples/sync/assistants/search_query.txt @@ -0,0 +1 @@ +Какова стоимость выездной пошлины для путешествия в чарующие и солнечные МАЛЬДИВЫ, где беззаботный отдых на восхитительных пляжах, утопающих в лучах мягкого средиземноморского солнца, соединяется с открытием величественных исторических памятников и наслаждением изысканными ароматами местной кухни? diff --git a/examples/sync/assistants/threads.py b/examples/sync/assistants/threads.py new file mode 100755 index 0000000..f4db96a --- /dev/null +++ b/examples/sync/assistants/threads.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +from yandex_cloud_ml_sdk import YCloudML + + +def main() -> None: + sdk = YCloudML( + folder_id='b1ghsjum2v37c2un8h64', + service_map={ + 'ai-assistants': 'assistant.api.cloud.yandex.net' + } + ) + + thread = sdk.threads.create(name='foo', ttl_days=5, expiration_policy="static") + print(f"new {thread=}") + + second = sdk.threads.get(thread.id) + print(f"same as first, {second=}") + second.update(ttl_days=9) + print(f"with updated epiration config, {second=}") + + message = thread.write("content") + message2 = second.write("content2") + print(f"hey, we just writed {message=} and {message2} into the thread") + + print("and now we could read it:") + for message in thread: + print(f" {message=}") + print(f" {message.text=}\n") + + for thread in sdk.threads.list(): + print(f"deleting thread {thread=}") + thread.delete() + + +if __name__ == '__main__': + main() diff --git a/examples/sync/assistants/turkey_example.txt b/examples/sync/assistants/turkey_example.txt new file mode 100644 index 0000000..8ff4a7a --- /dev/null +++ b/examples/sync/assistants/turkey_example.txt @@ -0,0 +1,170 @@ +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ + +🌞 Побег в Анталью: Ваш идеальный отдых начинается здесь! 🌊 + +Представьте себе: мягкий шелест волн, ласковое солнце и невероятные пейзажи... Вас ждет прекрасная Анталья! Этот уголок Турции идеально сочетает в себе пляжный отдых, богатую культуру и удивительную природу. + +Ваши преимущества с нашим туром: + +🏖 Беззаботные дни на пляже: Песчаные и галечные пляжи Антальи славятся своей чистотой и красотой. Устройте себе расслабляющий день, погружаясь в теплые воды Средиземного моря. + +🏛 Исторические открытия: Откройте для себя чудеса древнего мира. Посетите античные города Аспендос и Перге, насладитесь прогулками по исторической части города – Калечи, где каждая улочка хранит свое секреты. + +🌿 Природные чудеса: Полюбуйтесь величественным водопадом Дюден, исследуйте горный массив Тавр и отправьтесь на экскурсию в национальный парк Олюдениз, где воздух напоен ароматами сосен. + +🍽 Некоторые изысканные угощения: Насладитесь вкуснейшей турецкой кухней с её множеством специй и ароматов. Отведайте аутентичные блюда в местных ресторанах и попробуйте свежайшие морепродукты. + +🎉 Активные и вечерние развлечения: Для любителей активного отдыха доступны водные виды спорта, а для тех, кто ищет веселья, города предлагает оживлённые ночные клубы и дискотеки. + +Въездная / выездная пошлина всего лишь 20 долларов в обе стороны !!! + +Всего лишь 20 долларов + +Приготовьтесь к незабываемому путешествию в сказочную Анталью, где каждый день станет для вас маленьким праздником! Свяжитесь с нами, чтобы забронировать ваш идеальный отпуск уже сегодня. 🌟 + +Анталья ждет вас! ✈️ From 3f129c06818fdffde3d7fca0f5b3828e539f160d Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 1 Nov 2024 18:07:12 +0300 Subject: [PATCH 12/13] Add temporary fix for assistants endpoints --- src/yandex_cloud_ml_sdk/_client.py | 22 +++++++++++++++---- .../_search_indexes/domain.py | 7 ++++-- src/yandex_cloud_ml_sdk/_types/operation.py | 17 +++++++++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/yandex_cloud_ml_sdk/_client.py b/src/yandex_cloud_ml_sdk/_client.py index 13d2d98..51919ae 100644 --- a/src/yandex_cloud_ml_sdk/_client.py +++ b/src/yandex_cloud_ml_sdk/_client.py @@ -58,6 +58,15 @@ def __init__( async def _init_service_map(self, timeout: float): credentials = grpc.ssl_channel_credentials() metadata = await self._get_metadata(auth_required=False, timeout=timeout, retry_kind=RetryKind.SINGLE) + + # XXX: assistants is not at https://api.cloud.yandex.net/endpoints yet + # But when it will be, this dict keys will be just overridden + # TODO: delete + self._service_map = { + 'ai-assistants': 'assistant.api.cloud.yandex.net', + 'ai-files': 'assistant.api.cloud.yandex.net', + } + async with grpc.aio.secure_channel( self._endpoint, credentials, @@ -115,7 +124,9 @@ def _new_channel(self, endpoint: str) -> grpc.aio.Channel: interceptors=self._interceptors, ) - async def _get_channel(self, stub_class: type[_T], timeout: float) -> grpc.aio.Channel: + async def _get_channel( + self, stub_class: type[_T], timeout: float, service_name: str | None = None + ) -> grpc.aio.Channel: if stub_class in self._channels: return self._channels[stub_class] @@ -123,7 +134,8 @@ async def _get_channel(self, stub_class: type[_T], timeout: float) -> grpc.aio.C if stub_class in self._channels: return self._channels[stub_class] - service_name: str = _service_for_ctor(stub_class) + if service_name is None: + service_name = _service_for_ctor(stub_class) if not self._service_map: await self._init_service_map(timeout=timeout) @@ -135,11 +147,13 @@ async def _get_channel(self, stub_class: type[_T], timeout: float) -> grpc.aio.C return channel @asynccontextmanager - async def get_service_stub(self, stub_class: type[_T], timeout: float) -> AsyncIterator[_T]: + async def get_service_stub( + self, stub_class: type[_T], timeout: float, service_name: str | None = None + ) -> AsyncIterator[_T]: # NB: right now get_service_stub is asynccontextmanager and it is unnecessary, # but in future if we will make some ChannelPool, it could be handy to know, # when "user" releases resource - channel = await self._get_channel(stub_class, timeout) + channel = await self._get_channel(stub_class, timeout, service_name=service_name) yield stub_class(channel) async def call_service_stream( diff --git a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py index 967bfd9..3397a92 100644 --- a/src/yandex_cloud_ml_sdk/_search_indexes/domain.py +++ b/src/yandex_cloud_ml_sdk/_search_indexes/domain.py @@ -67,7 +67,9 @@ async def _create_deferred( text_search_index=text_search_index, ) - async with self._client.get_service_stub(SearchIndexServiceStub, timeout=timeout) as stub: + async with self._client.get_service_stub( + SearchIndexServiceStub, timeout=timeout, service_name='ai-assistants' + ) as stub: response = await self._client.call_service( stub.Create, request, @@ -78,7 +80,8 @@ async def _create_deferred( return self._operation_type( id=response.id, sdk=self._sdk, - result_type=self._impl + result_type=self._impl, + service_name='ai-assistants', ) async def _get( diff --git a/src/yandex_cloud_ml_sdk/_types/operation.py b/src/yandex_cloud_ml_sdk/_types/operation.py index 706124d..e099bea 100644 --- a/src/yandex_cloud_ml_sdk/_types/operation.py +++ b/src/yandex_cloud_ml_sdk/_types/operation.py @@ -83,11 +83,14 @@ async def _wait( class BaseOperation(OperationInterface[ResultTypeT]): _last_known_status: OperationStatus | None - def __init__(self, sdk: BaseSDK, id: str, result_type: type[ResultTypeT]): # pylint: disable=redefined-builtin + def __init__( + self, sdk: BaseSDK, id: str, result_type: type[ResultTypeT], service_name: str | None = None + ): # pylint: disable=redefined-builtin self._id = id self._sdk = sdk self._result_type: type[BaseResult] = result_type self._last_known_status = None + self._service_name = service_name @property def id(self): @@ -99,7 +102,11 @@ def _client(self): async def _get_status(self, *, timeout: float = 60) -> OperationStatus: request = GetOperationRequest(operation_id=self.id) - async with self._client.get_service_stub(OperationServiceStub, timeout=timeout) as stub: + async with self._client.get_service_stub( + OperationServiceStub, + timeout=timeout, + service_name=self._service_name, + ) as stub: response = await self._client.call_service( stub.Get, request, @@ -142,7 +149,11 @@ async def _get_result(self, *, timeout: float = 60) -> ResultTypeT: async def _cancel(self, *, timeout: float = 60) -> OperationStatus: request = CancelOperationRequest(operation_id=self.id) - async with self._client.get_service_stub(OperationServiceStub, timeout=timeout) as stub: + async with self._client.get_service_stub( + OperationServiceStub, + timeout=timeout, + service_name=self._service_name, + ) as stub: response = await self._client.call_service( stub.Cancel, request, From 793540c635d5cc9461d89a5b6b3bd9c1fb347d4f Mon Sep 17 00:00:00 2001 From: Vladimir Lipkin Date: Fri, 1 Nov 2024 18:10:32 +0300 Subject: [PATCH 13/13] Remvoe endpoints from examples --- examples/async/assistants/assistant_with_search_index.py | 9 +-------- examples/async/assistants/assistants.py | 7 +------ examples/async/assistants/files.py | 7 +------ examples/async/assistants/runs.py | 7 +------ examples/async/assistants/search_indexes.py | 9 +-------- examples/async/assistants/threads.py | 7 +------ examples/sync/assistants/assistant_with_search_index.py | 9 +-------- examples/sync/assistants/assistants.py | 7 +------ examples/sync/assistants/files.py | 7 +------ examples/sync/assistants/runs.py | 7 +------ examples/sync/assistants/search_indexes.py | 9 +-------- examples/sync/assistants/threads.py | 7 +------ 12 files changed, 12 insertions(+), 80 deletions(-) diff --git a/examples/async/assistants/assistant_with_search_index.py b/examples/async/assistants/assistant_with_search_index.py index 99a3c5d..922f8c0 100755 --- a/examples/async/assistants/assistant_with_search_index.py +++ b/examples/async/assistants/assistant_with_search_index.py @@ -13,14 +13,7 @@ def local_path(path: str) -> pathlib.Path: async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net', - 'ai-files': 'assistant.api.cloud.yandex.net', - 'operation': 'assistant.api.cloud.yandex.net', - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') file_coros = ( sdk.files.upload( diff --git a/examples/async/assistants/assistants.py b/examples/async/assistants/assistants.py index 5617195..e63a479 100755 --- a/examples/async/assistants/assistants.py +++ b/examples/async/assistants/assistants.py @@ -8,12 +8,7 @@ async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') assistant = await sdk.assistants.create( 'yandexgpt', diff --git a/examples/async/assistants/files.py b/examples/async/assistants/files.py index 2c8dce0..c3a6a74 100755 --- a/examples/async/assistants/files.py +++ b/examples/async/assistants/files.py @@ -9,12 +9,7 @@ async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-files': 'assistant.api.cloud.yandex.net' - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') path = pathlib.Path(__file__).parent / 'example_file' file = await sdk.files.upload(path, ttl_days=5, expiration_policy="static") diff --git a/examples/async/assistants/runs.py b/examples/async/assistants/runs.py index 9832581..4fc334d 100755 --- a/examples/async/assistants/runs.py +++ b/examples/async/assistants/runs.py @@ -8,12 +8,7 @@ async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') assistant = await sdk.assistants.create( 'yandexgpt', diff --git a/examples/async/assistants/search_indexes.py b/examples/async/assistants/search_indexes.py index 6dbf0a1..98acdda 100755 --- a/examples/async/assistants/search_indexes.py +++ b/examples/async/assistants/search_indexes.py @@ -14,14 +14,7 @@ def local_path(path: str) -> pathlib.Path: async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-files': 'assistant.api.cloud.yandex.net', - 'ai-assistants': 'assistant.api.cloud.yandex.net', - 'operation': 'assistant.api.cloud.yandex.net', - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') file_coros = ( sdk.files.upload( diff --git a/examples/async/assistants/threads.py b/examples/async/assistants/threads.py index e5cbed1..af7be03 100755 --- a/examples/async/assistants/threads.py +++ b/examples/async/assistants/threads.py @@ -8,12 +8,7 @@ async def main() -> None: - sdk = AsyncYCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = AsyncYCloudML(folder_id='b1ghsjum2v37c2un8h64') thread = await sdk.threads.create(name='foo', ttl_days=5, expiration_policy="static") print(f"new {thread=}") diff --git a/examples/sync/assistants/assistant_with_search_index.py b/examples/sync/assistants/assistant_with_search_index.py index 8daf80e..4431c37 100755 --- a/examples/sync/assistants/assistant_with_search_index.py +++ b/examples/sync/assistants/assistant_with_search_index.py @@ -12,14 +12,7 @@ def local_path(path: str) -> pathlib.Path: def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net', - 'ai-files': 'assistant.api.cloud.yandex.net', - 'operation': 'assistant.api.cloud.yandex.net', - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') files = [] for path in ['turkey_example.txt', 'maldives_example.txt']: diff --git a/examples/sync/assistants/assistants.py b/examples/sync/assistants/assistants.py index 46a0e25..90d2648 100755 --- a/examples/sync/assistants/assistants.py +++ b/examples/sync/assistants/assistants.py @@ -6,12 +6,7 @@ def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') assistant = sdk.assistants.create( 'yandexgpt', diff --git a/examples/sync/assistants/files.py b/examples/sync/assistants/files.py index 704638e..e9dc707 100755 --- a/examples/sync/assistants/files.py +++ b/examples/sync/assistants/files.py @@ -8,12 +8,7 @@ def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-files': 'assistant.api.cloud.yandex.net' - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') path = pathlib.Path(__file__).parent / 'example_file' file = sdk.files.upload(path, ttl_days=5, expiration_policy="static") diff --git a/examples/sync/assistants/runs.py b/examples/sync/assistants/runs.py index 1bea6fa..60a9256 100755 --- a/examples/sync/assistants/runs.py +++ b/examples/sync/assistants/runs.py @@ -6,12 +6,7 @@ def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') assistant = sdk.assistants.create( 'yandexgpt', diff --git a/examples/sync/assistants/search_indexes.py b/examples/sync/assistants/search_indexes.py index 1b4741a..cc9b59d 100755 --- a/examples/sync/assistants/search_indexes.py +++ b/examples/sync/assistants/search_indexes.py @@ -13,14 +13,7 @@ def local_path(path: str) -> pathlib.Path: def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-files': 'assistant.api.cloud.yandex.net', - 'ai-assistants': 'assistant.api.cloud.yandex.net', - 'operation': 'assistant.api.cloud.yandex.net', - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') files = [] for path in ['turkey_example.txt', 'maldives_example.txt']: diff --git a/examples/sync/assistants/threads.py b/examples/sync/assistants/threads.py index f4db96a..7cc2f86 100755 --- a/examples/sync/assistants/threads.py +++ b/examples/sync/assistants/threads.py @@ -6,12 +6,7 @@ def main() -> None: - sdk = YCloudML( - folder_id='b1ghsjum2v37c2un8h64', - service_map={ - 'ai-assistants': 'assistant.api.cloud.yandex.net' - } - ) + sdk = YCloudML(folder_id='b1ghsjum2v37c2un8h64') thread = sdk.threads.create(name='foo', ttl_days=5, expiration_policy="static") print(f"new {thread=}")