diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 548f070..7da1c21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,10 @@ jobs: - name: Run lints run: ./scripts/lint - upload: + build: if: github.repository == 'stainless-sdks/opencode-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 - name: upload + name: build permissions: contents: read id-token: write @@ -46,6 +46,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + - name: Get GitHub OIDC Token id: github-oidc uses: actions/github-script@v6 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4f9005e..b5db7ce 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.6" + ".": "0.1.0-alpha.7" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 3857fb8..07e475c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-384a94f70b48c84af9eddcac72bbe12952c3ae3bd7fededfa1c63b203d12d828.yml -openapi_spec_hash: e47ad28d646736d5d79d2dd1086d517d -config_hash: e2d21e779cfc4e26a99b9e4e75de3f50 +configured_endpoints: 20 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-e2f67adede4455c3fe4507ac6f0b2ed1a91ee951ab30e01179555c18765750d4.yml +openapi_spec_hash: 6005bcfff58c025d61739be42030a339 +config_hash: 6c8822d278ba83456e5eed6d774ca230 diff --git a/CHANGELOG.md b/CHANGELOG.md index 80a92df..71c8a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.1.0-alpha.7 (2025-07-02) + +Full Changelog: [v0.1.0-alpha.6...v0.1.0-alpha.7](https://github.com/sst/opencode-sdk-python/compare/v0.1.0-alpha.6...v0.1.0-alpha.7) + +### Features + +* **api:** update via SDK Studio ([84628c0](https://github.com/sst/opencode-sdk-python/commit/84628c0bd3cd508832f04db0fd8a6cd5367dddf3)) + + +### Chores + +* **ci:** change upload type ([f3019c9](https://github.com/sst/opencode-sdk-python/commit/f3019c94cb548e436b2d7d884969a90db4649f80)) + ## 0.1.0-alpha.6 (2025-06-30) Full Changelog: [v0.1.0-alpha.5...v0.1.0-alpha.6](https://github.com/sst/opencode-sdk-python/compare/v0.1.0-alpha.5...v0.1.0-alpha.6) diff --git a/api.md b/api.md index 9a9f536..3d16f35 100644 --- a/api.md +++ b/api.md @@ -29,17 +29,32 @@ Methods: - client.app.get() -> App - client.app.init() -> AppInitResponse +# Find + +Types: + +```python +from opencode_ai.types import FindFilesResponse, FindSymbolsResponse, FindTextResponse +``` + +Methods: + +- client.find.files(\*\*params) -> FindFilesResponse +- client.find.symbols(\*\*params) -> FindSymbolsResponse +- client.find.text(\*\*params) -> FindTextResponse + # File Types: ```python -from opencode_ai.types import FileSearchResponse +from opencode_ai.types import FileReadResponse, FileStatusResponse ``` Methods: -- client.file.search(\*\*params) -> FileSearchResponse +- client.file.read(\*\*params) -> FileReadResponse +- client.file.status() -> FileStatusResponse # Config diff --git a/pyproject.toml b/pyproject.toml index 6c7f406..fbfef4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "opencode-ai" -version = "0.1.0-alpha.6" +version = "0.1.0-alpha.7" description = "The official Python library for the opencode API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 1c10fa0..c16f6af 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -exuo pipefail -RESPONSE=$(curl -X POST "$URL" \ +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ -H "Authorization: Bearer $AUTH" \ -H "Content-Type: application/json") @@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ - -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install --pre 'https://pkg.stainless.com/s/opencode-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/opencode-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 diff --git a/src/opencode_ai/_client.py b/src/opencode_ai/_client.py index c97685d..b162cc3 100644 --- a/src/opencode_ai/_client.py +++ b/src/opencode_ai/_client.py @@ -21,7 +21,7 @@ ) from ._utils import is_given, get_async_library from ._version import __version__ -from .resources import app, file, event, config, session +from .resources import app, file, find, event, config, session from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError from ._base_client import ( @@ -45,6 +45,7 @@ class Opencode(SyncAPIClient): event: event.EventResource app: app.AppResource + find: find.FindResource file: file.FileResource config: config.ConfigResource session: session.SessionResource @@ -96,6 +97,7 @@ def __init__( self.event = event.EventResource(self) self.app = app.AppResource(self) + self.find = find.FindResource(self) self.file = file.FileResource(self) self.config = config.ConfigResource(self) self.session = session.SessionResource(self) @@ -202,6 +204,7 @@ def _make_status_error( class AsyncOpencode(AsyncAPIClient): event: event.AsyncEventResource app: app.AsyncAppResource + find: find.AsyncFindResource file: file.AsyncFileResource config: config.AsyncConfigResource session: session.AsyncSessionResource @@ -253,6 +256,7 @@ def __init__( self.event = event.AsyncEventResource(self) self.app = app.AsyncAppResource(self) + self.find = find.AsyncFindResource(self) self.file = file.AsyncFileResource(self) self.config = config.AsyncConfigResource(self) self.session = session.AsyncSessionResource(self) @@ -360,6 +364,7 @@ class OpencodeWithRawResponse: def __init__(self, client: Opencode) -> None: self.event = event.EventResourceWithRawResponse(client.event) self.app = app.AppResourceWithRawResponse(client.app) + self.find = find.FindResourceWithRawResponse(client.find) self.file = file.FileResourceWithRawResponse(client.file) self.config = config.ConfigResourceWithRawResponse(client.config) self.session = session.SessionResourceWithRawResponse(client.session) @@ -369,6 +374,7 @@ class AsyncOpencodeWithRawResponse: def __init__(self, client: AsyncOpencode) -> None: self.event = event.AsyncEventResourceWithRawResponse(client.event) self.app = app.AsyncAppResourceWithRawResponse(client.app) + self.find = find.AsyncFindResourceWithRawResponse(client.find) self.file = file.AsyncFileResourceWithRawResponse(client.file) self.config = config.AsyncConfigResourceWithRawResponse(client.config) self.session = session.AsyncSessionResourceWithRawResponse(client.session) @@ -378,6 +384,7 @@ class OpencodeWithStreamedResponse: def __init__(self, client: Opencode) -> None: self.event = event.EventResourceWithStreamingResponse(client.event) self.app = app.AppResourceWithStreamingResponse(client.app) + self.find = find.FindResourceWithStreamingResponse(client.find) self.file = file.FileResourceWithStreamingResponse(client.file) self.config = config.ConfigResourceWithStreamingResponse(client.config) self.session = session.SessionResourceWithStreamingResponse(client.session) @@ -387,6 +394,7 @@ class AsyncOpencodeWithStreamedResponse: def __init__(self, client: AsyncOpencode) -> None: self.event = event.AsyncEventResourceWithStreamingResponse(client.event) self.app = app.AsyncAppResourceWithStreamingResponse(client.app) + self.find = find.AsyncFindResourceWithStreamingResponse(client.find) self.file = file.AsyncFileResourceWithStreamingResponse(client.file) self.config = config.AsyncConfigResourceWithStreamingResponse(client.config) self.session = session.AsyncSessionResourceWithStreamingResponse(client.session) diff --git a/src/opencode_ai/_version.py b/src/opencode_ai/_version.py index 3df8319..3de1cfa 100644 --- a/src/opencode_ai/_version.py +++ b/src/opencode_ai/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "opencode_ai" -__version__ = "0.1.0-alpha.6" # x-release-please-version +__version__ = "0.1.0-alpha.7" # x-release-please-version diff --git a/src/opencode_ai/resources/__init__.py b/src/opencode_ai/resources/__init__.py index 6cb6dfd..7b0815f 100644 --- a/src/opencode_ai/resources/__init__.py +++ b/src/opencode_ai/resources/__init__.py @@ -16,6 +16,14 @@ FileResourceWithStreamingResponse, AsyncFileResourceWithStreamingResponse, ) +from .find import ( + FindResource, + AsyncFindResource, + FindResourceWithRawResponse, + AsyncFindResourceWithRawResponse, + FindResourceWithStreamingResponse, + AsyncFindResourceWithStreamingResponse, +) from .event import ( EventResource, AsyncEventResource, @@ -54,6 +62,12 @@ "AsyncAppResourceWithRawResponse", "AppResourceWithStreamingResponse", "AsyncAppResourceWithStreamingResponse", + "FindResource", + "AsyncFindResource", + "FindResourceWithRawResponse", + "AsyncFindResourceWithRawResponse", + "FindResourceWithStreamingResponse", + "AsyncFindResourceWithStreamingResponse", "FileResource", "AsyncFileResource", "FileResourceWithRawResponse", diff --git a/src/opencode_ai/resources/file.py b/src/opencode_ai/resources/file.py index a5b5fc2..464bb93 100644 --- a/src/opencode_ai/resources/file.py +++ b/src/opencode_ai/resources/file.py @@ -4,7 +4,7 @@ import httpx -from ..types import file_search_params +from ..types import file_read_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -16,7 +16,8 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.file_search_response import FileSearchResponse +from ..types.file_read_response import FileReadResponse +from ..types.file_status_response import FileStatusResponse __all__ = ["FileResource", "AsyncFileResource"] @@ -41,19 +42,19 @@ def with_streaming_response(self) -> FileResourceWithStreamingResponse: """ return FileResourceWithStreamingResponse(self) - def search( + def read( self, *, - query: str, + path: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FileSearchResponse: + ) -> FileReadResponse: """ - Search for files + Read a file Args: extra_headers: Send extra headers @@ -71,9 +72,28 @@ def search( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"query": query}, file_search_params.FileSearchParams), + query=maybe_transform({"path": path}, file_read_params.FileReadParams), ), - cast_to=FileSearchResponse, + cast_to=FileReadResponse, + ) + + def status( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileStatusResponse: + """Get file status""" + return self._get( + "/file/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FileStatusResponse, ) @@ -97,19 +117,19 @@ def with_streaming_response(self) -> AsyncFileResourceWithStreamingResponse: """ return AsyncFileResourceWithStreamingResponse(self) - async def search( + async def read( self, *, - query: str, + path: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FileSearchResponse: + ) -> FileReadResponse: """ - Search for files + Read a file Args: extra_headers: Send extra headers @@ -127,9 +147,28 @@ async def search( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform({"query": query}, file_search_params.FileSearchParams), + query=await async_maybe_transform({"path": path}, file_read_params.FileReadParams), + ), + cast_to=FileReadResponse, + ) + + async def status( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FileStatusResponse: + """Get file status""" + return await self._get( + "/file/status", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=FileSearchResponse, + cast_to=FileStatusResponse, ) @@ -137,8 +176,11 @@ class FileResourceWithRawResponse: def __init__(self, file: FileResource) -> None: self._file = file - self.search = to_raw_response_wrapper( - file.search, + self.read = to_raw_response_wrapper( + file.read, + ) + self.status = to_raw_response_wrapper( + file.status, ) @@ -146,8 +188,11 @@ class AsyncFileResourceWithRawResponse: def __init__(self, file: AsyncFileResource) -> None: self._file = file - self.search = async_to_raw_response_wrapper( - file.search, + self.read = async_to_raw_response_wrapper( + file.read, + ) + self.status = async_to_raw_response_wrapper( + file.status, ) @@ -155,8 +200,11 @@ class FileResourceWithStreamingResponse: def __init__(self, file: FileResource) -> None: self._file = file - self.search = to_streamed_response_wrapper( - file.search, + self.read = to_streamed_response_wrapper( + file.read, + ) + self.status = to_streamed_response_wrapper( + file.status, ) @@ -164,6 +212,9 @@ class AsyncFileResourceWithStreamingResponse: def __init__(self, file: AsyncFileResource) -> None: self._file = file - self.search = async_to_streamed_response_wrapper( - file.search, + self.read = async_to_streamed_response_wrapper( + file.read, + ) + self.status = async_to_streamed_response_wrapper( + file.status, ) diff --git a/src/opencode_ai/resources/find.py b/src/opencode_ai/resources/find.py new file mode 100644 index 0000000..1558e7c --- /dev/null +++ b/src/opencode_ai/resources/find.py @@ -0,0 +1,335 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import find_text_params, find_files_params, find_symbols_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.find_text_response import FindTextResponse +from ..types.find_files_response import FindFilesResponse +from ..types.find_symbols_response import FindSymbolsResponse + +__all__ = ["FindResource", "AsyncFindResource"] + + +class FindResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FindResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/sst/opencode-sdk-python#accessing-raw-response-data-eg-headers + """ + return FindResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FindResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/sst/opencode-sdk-python#with_streaming_response + """ + return FindResourceWithStreamingResponse(self) + + def files( + self, + *, + query: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindFilesResponse: + """ + Find files + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/find/file", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"query": query}, find_files_params.FindFilesParams), + ), + cast_to=FindFilesResponse, + ) + + def symbols( + self, + *, + query: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindSymbolsResponse: + """ + Find workspace symbols + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/find/symbol", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"query": query}, find_symbols_params.FindSymbolsParams), + ), + cast_to=FindSymbolsResponse, + ) + + def text( + self, + *, + pattern: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindTextResponse: + """ + Find text in files + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/find", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"pattern": pattern}, find_text_params.FindTextParams), + ), + cast_to=FindTextResponse, + ) + + +class AsyncFindResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFindResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/sst/opencode-sdk-python#accessing-raw-response-data-eg-headers + """ + return AsyncFindResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFindResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/sst/opencode-sdk-python#with_streaming_response + """ + return AsyncFindResourceWithStreamingResponse(self) + + async def files( + self, + *, + query: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindFilesResponse: + """ + Find files + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/find/file", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"query": query}, find_files_params.FindFilesParams), + ), + cast_to=FindFilesResponse, + ) + + async def symbols( + self, + *, + query: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindSymbolsResponse: + """ + Find workspace symbols + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/find/symbol", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"query": query}, find_symbols_params.FindSymbolsParams), + ), + cast_to=FindSymbolsResponse, + ) + + async def text( + self, + *, + pattern: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> FindTextResponse: + """ + Find text in files + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/find", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"pattern": pattern}, find_text_params.FindTextParams), + ), + cast_to=FindTextResponse, + ) + + +class FindResourceWithRawResponse: + def __init__(self, find: FindResource) -> None: + self._find = find + + self.files = to_raw_response_wrapper( + find.files, + ) + self.symbols = to_raw_response_wrapper( + find.symbols, + ) + self.text = to_raw_response_wrapper( + find.text, + ) + + +class AsyncFindResourceWithRawResponse: + def __init__(self, find: AsyncFindResource) -> None: + self._find = find + + self.files = async_to_raw_response_wrapper( + find.files, + ) + self.symbols = async_to_raw_response_wrapper( + find.symbols, + ) + self.text = async_to_raw_response_wrapper( + find.text, + ) + + +class FindResourceWithStreamingResponse: + def __init__(self, find: FindResource) -> None: + self._find = find + + self.files = to_streamed_response_wrapper( + find.files, + ) + self.symbols = to_streamed_response_wrapper( + find.symbols, + ) + self.text = to_streamed_response_wrapper( + find.text, + ) + + +class AsyncFindResourceWithStreamingResponse: + def __init__(self, find: AsyncFindResource) -> None: + self._find = find + + self.files = async_to_streamed_response_wrapper( + find.files, + ) + self.symbols = async_to_streamed_response_wrapper( + find.symbols, + ) + self.text = async_to_streamed_response_wrapper( + find.text, + ) diff --git a/src/opencode_ai/types/__init__.py b/src/opencode_ai/types/__init__.py index 6ab3485..edf0bf8 100644 --- a/src/opencode_ai/types/__init__.py +++ b/src/opencode_ai/types/__init__.py @@ -23,17 +23,24 @@ from .step_start_part import StepStartPart as StepStartPart from .text_part_param import TextPartParam as TextPartParam from .tool_call_param import ToolCallParam as ToolCallParam +from .file_read_params import FileReadParams as FileReadParams +from .find_text_params import FindTextParams as FindTextParams from .app_init_response import AppInitResponse as AppInitResponse +from .find_files_params import FindFilesParams as FindFilesParams from .tool_partial_call import ToolPartialCall as ToolPartialCall from .tool_result_param import ToolResultParam as ToolResultParam -from .file_search_params import FileSearchParams as FileSearchParams +from .file_read_response import FileReadResponse as FileReadResponse +from .find_text_response import FindTextResponse as FindTextResponse from .message_part_param import MessagePartParam as MessagePartParam from .event_list_response import EventListResponse as EventListResponse +from .find_files_response import FindFilesResponse as FindFilesResponse +from .find_symbols_params import FindSymbolsParams as FindSymbolsParams from .session_chat_params import SessionChatParams as SessionChatParams from .session_init_params import SessionInitParams as SessionInitParams -from .file_search_response import FileSearchResponse as FileSearchResponse +from .file_status_response import FileStatusResponse as FileStatusResponse from .reasoning_part_param import ReasoningPartParam as ReasoningPartParam from .tool_invocation_part import ToolInvocationPart as ToolInvocationPart +from .find_symbols_response import FindSymbolsResponse as FindSymbolsResponse from .session_init_response import SessionInitResponse as SessionInitResponse from .session_list_response import SessionListResponse as SessionListResponse from .source_url_part_param import SourceURLPartParam as SourceURLPartParam diff --git a/src/opencode_ai/types/event_list_response.py b/src/opencode_ai/types/event_list_response.py index 79e2e64..e824507 100644 --- a/src/opencode_ai/types/event_list_response.py +++ b/src/opencode_ai/types/event_list_response.py @@ -40,6 +40,8 @@ "EventSessionErrorProperties", "EventSessionErrorPropertiesError", "EventSessionErrorPropertiesErrorMessageOutputLengthError", + "EventFileWatcherUpdated", + "EventFileWatcherUpdatedProperties", ] @@ -185,6 +187,18 @@ class EventSessionError(BaseModel): type: Literal["session.error"] +class EventFileWatcherUpdatedProperties(BaseModel): + event: Literal["rename", "change"] + + file: str + + +class EventFileWatcherUpdated(BaseModel): + properties: EventFileWatcherUpdatedProperties + + type: Literal["file.watcher.updated"] + + EventListResponse: TypeAlias = Annotated[ Union[ EventLspClientDiagnostics, @@ -198,6 +212,7 @@ class EventSessionError(BaseModel): EventSessionDeleted, EventSessionIdle, EventSessionError, + EventFileWatcherUpdated, ], PropertyInfo(discriminator="type"), ] diff --git a/src/opencode_ai/types/file_read_params.py b/src/opencode_ai/types/file_read_params.py new file mode 100644 index 0000000..b251a07 --- /dev/null +++ b/src/opencode_ai/types/file_read_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["FileReadParams"] + + +class FileReadParams(TypedDict, total=False): + path: Required[str] diff --git a/src/opencode_ai/types/file_read_response.py b/src/opencode_ai/types/file_read_response.py new file mode 100644 index 0000000..5392a07 --- /dev/null +++ b/src/opencode_ai/types/file_read_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["FileReadResponse"] + + +class FileReadResponse(BaseModel): + content: str + + type: Literal["raw", "patch"] diff --git a/src/opencode_ai/types/file_status_response.py b/src/opencode_ai/types/file_status_response.py new file mode 100644 index 0000000..af14843 --- /dev/null +++ b/src/opencode_ai/types/file_status_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal, TypeAlias + +from .._models import BaseModel + +__all__ = ["FileStatusResponse", "FileStatusResponseItem"] + + +class FileStatusResponseItem(BaseModel): + added: float + + file: str + + removed: float + + status: Literal["added", "deleted", "modified"] + + +FileStatusResponse: TypeAlias = List[FileStatusResponseItem] diff --git a/src/opencode_ai/types/file_search_params.py b/src/opencode_ai/types/find_files_params.py similarity index 71% rename from src/opencode_ai/types/file_search_params.py rename to src/opencode_ai/types/find_files_params.py index e08021e..c2b3093 100644 --- a/src/opencode_ai/types/file_search_params.py +++ b/src/opencode_ai/types/find_files_params.py @@ -4,8 +4,8 @@ from typing_extensions import Required, TypedDict -__all__ = ["FileSearchParams"] +__all__ = ["FindFilesParams"] -class FileSearchParams(TypedDict, total=False): +class FindFilesParams(TypedDict, total=False): query: Required[str] diff --git a/src/opencode_ai/types/file_search_response.py b/src/opencode_ai/types/find_files_response.py similarity index 67% rename from src/opencode_ai/types/file_search_response.py rename to src/opencode_ai/types/find_files_response.py index 563eb33..2b408de 100644 --- a/src/opencode_ai/types/file_search_response.py +++ b/src/opencode_ai/types/find_files_response.py @@ -3,6 +3,6 @@ from typing import List from typing_extensions import TypeAlias -__all__ = ["FileSearchResponse"] +__all__ = ["FindFilesResponse"] -FileSearchResponse: TypeAlias = List[str] +FindFilesResponse: TypeAlias = List[str] diff --git a/src/opencode_ai/types/find_symbols_params.py b/src/opencode_ai/types/find_symbols_params.py new file mode 100644 index 0000000..60f9e9e --- /dev/null +++ b/src/opencode_ai/types/find_symbols_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["FindSymbolsParams"] + + +class FindSymbolsParams(TypedDict, total=False): + query: Required[str] diff --git a/src/opencode_ai/types/find_symbols_response.py b/src/opencode_ai/types/find_symbols_response.py new file mode 100644 index 0000000..3f25235 --- /dev/null +++ b/src/opencode_ai/types/find_symbols_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +__all__ = ["FindSymbolsResponse"] + +FindSymbolsResponse: TypeAlias = List[object] diff --git a/src/opencode_ai/types/find_text_params.py b/src/opencode_ai/types/find_text_params.py new file mode 100644 index 0000000..f35ea4f --- /dev/null +++ b/src/opencode_ai/types/find_text_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["FindTextParams"] + + +class FindTextParams(TypedDict, total=False): + pattern: Required[str] diff --git a/src/opencode_ai/types/find_text_response.py b/src/opencode_ai/types/find_text_response.py new file mode 100644 index 0000000..4557834 --- /dev/null +++ b/src/opencode_ai/types/find_text_response.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .._models import BaseModel + +__all__ = [ + "FindTextResponse", + "FindTextResponseItem", + "FindTextResponseItemLines", + "FindTextResponseItemPath", + "FindTextResponseItemSubmatch", + "FindTextResponseItemSubmatchMatch", +] + + +class FindTextResponseItemLines(BaseModel): + text: str + + +class FindTextResponseItemPath(BaseModel): + text: str + + +class FindTextResponseItemSubmatchMatch(BaseModel): + text: str + + +class FindTextResponseItemSubmatch(BaseModel): + end: float + + match: FindTextResponseItemSubmatchMatch + + start: float + + +class FindTextResponseItem(BaseModel): + absolute_offset: float + + line_number: float + + lines: FindTextResponseItemLines + + path: FindTextResponseItemPath + + submatches: List[FindTextResponseItemSubmatch] + + +FindTextResponse: TypeAlias = List[FindTextResponseItem] diff --git a/src/opencode_ai/types/message.py b/src/opencode_ai/types/message.py index 096b43b..e1af6fb 100644 --- a/src/opencode_ai/types/message.py +++ b/src/opencode_ai/types/message.py @@ -23,6 +23,7 @@ "MetadataAssistantTokensCache", "MetadataError", "MetadataErrorMessageOutputLengthError", + "MetadataUser", ] @@ -99,6 +100,10 @@ class MetadataErrorMessageOutputLengthError(BaseModel): ] +class MetadataUser(BaseModel): + snapshot: Optional[str] = None + + class Metadata(BaseModel): session_id: str = FieldInfo(alias="sessionID") @@ -110,6 +115,8 @@ class Metadata(BaseModel): error: Optional[MetadataError] = None + user: Optional[MetadataUser] = None + class Message(BaseModel): id: str diff --git a/tests/api_resources/test_file.py b/tests/api_resources/test_file.py index 2e8d52b..7298335 100644 --- a/tests/api_resources/test_file.py +++ b/tests/api_resources/test_file.py @@ -9,7 +9,7 @@ from opencode_ai import Opencode, AsyncOpencode from tests.utils import assert_matches_type -from opencode_ai.types import FileSearchResponse +from opencode_ai.types import FileReadResponse, FileStatusResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -19,35 +19,63 @@ class TestFile: @pytest.mark.skip() @parametrize - def test_method_search(self, client: Opencode) -> None: - file = client.file.search( - query="query", + def test_method_read(self, client: Opencode) -> None: + file = client.file.read( + path="path", ) - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) @pytest.mark.skip() @parametrize - def test_raw_response_search(self, client: Opencode) -> None: - response = client.file.with_raw_response.search( - query="query", + def test_raw_response_read(self, client: Opencode) -> None: + response = client.file.with_raw_response.read( + path="path", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) @pytest.mark.skip() @parametrize - def test_streaming_response_search(self, client: Opencode) -> None: - with client.file.with_streaming_response.search( - query="query", + def test_streaming_response_read(self, client: Opencode) -> None: + with client.file.with_streaming_response.read( + path="path", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_status(self, client: Opencode) -> None: + file = client.file.status() + assert_matches_type(FileStatusResponse, file, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_status(self, client: Opencode) -> None: + response = client.file.with_raw_response.status() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() + assert_matches_type(FileStatusResponse, file, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_status(self, client: Opencode) -> None: + with client.file.with_streaming_response.status() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = response.parse() + assert_matches_type(FileStatusResponse, file, path=["response"]) assert cast(Any, response.is_closed) is True @@ -59,34 +87,62 @@ class TestAsyncFile: @pytest.mark.skip() @parametrize - async def test_method_search(self, async_client: AsyncOpencode) -> None: - file = await async_client.file.search( - query="query", + async def test_method_read(self, async_client: AsyncOpencode) -> None: + file = await async_client.file.read( + path="path", ) - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) @pytest.mark.skip() @parametrize - async def test_raw_response_search(self, async_client: AsyncOpencode) -> None: - response = await async_client.file.with_raw_response.search( - query="query", + async def test_raw_response_read(self, async_client: AsyncOpencode) -> None: + response = await async_client.file.with_raw_response.read( + path="path", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = await response.parse() - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) @pytest.mark.skip() @parametrize - async def test_streaming_response_search(self, async_client: AsyncOpencode) -> None: - async with async_client.file.with_streaming_response.search( - query="query", + async def test_streaming_response_read(self, async_client: AsyncOpencode) -> None: + async with async_client.file.with_streaming_response.read( + path="path", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = await response.parse() - assert_matches_type(FileSearchResponse, file, path=["response"]) + assert_matches_type(FileReadResponse, file, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_status(self, async_client: AsyncOpencode) -> None: + file = await async_client.file.status() + assert_matches_type(FileStatusResponse, file, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_status(self, async_client: AsyncOpencode) -> None: + response = await async_client.file.with_raw_response.status() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = await response.parse() + assert_matches_type(FileStatusResponse, file, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_status(self, async_client: AsyncOpencode) -> None: + async with async_client.file.with_streaming_response.status() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file = await response.parse() + assert_matches_type(FileStatusResponse, file, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_find.py b/tests/api_resources/test_find.py new file mode 100644 index 0000000..fe40d85 --- /dev/null +++ b/tests/api_resources/test_find.py @@ -0,0 +1,232 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from opencode_ai import Opencode, AsyncOpencode +from tests.utils import assert_matches_type +from opencode_ai.types import ( + FindTextResponse, + FindFilesResponse, + FindSymbolsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFind: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_files(self, client: Opencode) -> None: + find = client.find.files( + query="query", + ) + assert_matches_type(FindFilesResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_files(self, client: Opencode) -> None: + response = client.find.with_raw_response.files( + query="query", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = response.parse() + assert_matches_type(FindFilesResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_files(self, client: Opencode) -> None: + with client.find.with_streaming_response.files( + query="query", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = response.parse() + assert_matches_type(FindFilesResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_symbols(self, client: Opencode) -> None: + find = client.find.symbols( + query="query", + ) + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_symbols(self, client: Opencode) -> None: + response = client.find.with_raw_response.symbols( + query="query", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = response.parse() + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_symbols(self, client: Opencode) -> None: + with client.find.with_streaming_response.symbols( + query="query", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = response.parse() + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_text(self, client: Opencode) -> None: + find = client.find.text( + pattern="pattern", + ) + assert_matches_type(FindTextResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_text(self, client: Opencode) -> None: + response = client.find.with_raw_response.text( + pattern="pattern", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = response.parse() + assert_matches_type(FindTextResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_text(self, client: Opencode) -> None: + with client.find.with_streaming_response.text( + pattern="pattern", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = response.parse() + assert_matches_type(FindTextResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncFind: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip() + @parametrize + async def test_method_files(self, async_client: AsyncOpencode) -> None: + find = await async_client.find.files( + query="query", + ) + assert_matches_type(FindFilesResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_files(self, async_client: AsyncOpencode) -> None: + response = await async_client.find.with_raw_response.files( + query="query", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = await response.parse() + assert_matches_type(FindFilesResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_files(self, async_client: AsyncOpencode) -> None: + async with async_client.find.with_streaming_response.files( + query="query", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = await response.parse() + assert_matches_type(FindFilesResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_symbols(self, async_client: AsyncOpencode) -> None: + find = await async_client.find.symbols( + query="query", + ) + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_symbols(self, async_client: AsyncOpencode) -> None: + response = await async_client.find.with_raw_response.symbols( + query="query", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = await response.parse() + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_symbols(self, async_client: AsyncOpencode) -> None: + async with async_client.find.with_streaming_response.symbols( + query="query", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = await response.parse() + assert_matches_type(FindSymbolsResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_text(self, async_client: AsyncOpencode) -> None: + find = await async_client.find.text( + pattern="pattern", + ) + assert_matches_type(FindTextResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_text(self, async_client: AsyncOpencode) -> None: + response = await async_client.find.with_raw_response.text( + pattern="pattern", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + find = await response.parse() + assert_matches_type(FindTextResponse, find, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_text(self, async_client: AsyncOpencode) -> None: + async with async_client.find.with_streaming_response.text( + pattern="pattern", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + find = await response.parse() + assert_matches_type(FindTextResponse, find, path=["response"]) + + assert cast(Any, response.is_closed) is True