diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf85fadee..b7512d114 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' @@ -17,7 +19,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/structify-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@v6 @@ -36,7 +38,7 @@ jobs: run: ./scripts/lint build: - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') timeout-minutes: 10 name: build permissions: @@ -61,14 +63,18 @@ jobs: run: rye build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/structify-python' + if: |- + github.repository == 'stainless-sdks/structify-python' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/structify-python' + if: |- + github.repository == 'stainless-sdks/structify-python' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.gitignore b/.gitignore index 95ceb189a..3824f4c48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log _dev __pycache__ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4d3d04fcb..592985c16 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.183.0" + ".": "1.184.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index fa94e3025..45591bca0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 234 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/structify%2Fstructify-1e6c4fd0edc3495bc88e8e124a41a7598a682123854f9e9daabc54192f8f976c.yml -openapi_spec_hash: 8ded4b078445c04fa30d205bcbadc1e5 -config_hash: 165b687c958e22430204bd5ef9094d9a +configured_endpoints: 257 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/structify%2Fstructify-98b70908fefea6e8700e8b59027706c7243ed385df23a6d9677229bde75d0f66.yml +openapi_spec_hash: c0683fd6f52b8e1ee90ac4c17a908d88 +config_hash: 5a7e7204a5ad7239167be965bb256616 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f1d6ced3..2385ff3f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,123 @@ # Changelog +## 1.184.0 (2026-03-27) + +Full Changelog: [v1.183.0...v1.184.0](https://github.com/StructifyAI/structify-python/compare/v1.183.0...v1.184.0) + +### Features + +* **api:** api update ([60cf087](https://github.com/StructifyAI/structify-python/commit/60cf0874a5e1299c02ca7dea7118ae831c51e6ef)) +* **internal:** implement indices array format for query and form serialization ([6d5a683](https://github.com/StructifyAI/structify-python/commit/6d5a683526efc84586e87f86bf187aed79d2be5b)) +* Update from Structify backend changes ([38c6730](https://github.com/StructifyAI/structify-python/commit/38c67302a084c70b535aa9bbb6594d881e462281)) +* Update from Structify backend changes ([22b7aeb](https://github.com/StructifyAI/structify-python/commit/22b7aeb09997b0d7b8e4320bb5e37860f78874ae)) +* Update from Structify backend changes ([5e74183](https://github.com/StructifyAI/structify-python/commit/5e74183af52a15223e47a86c12e278fa9baae23e)) +* Update from Structify backend changes ([2957a79](https://github.com/StructifyAI/structify-python/commit/2957a7945ff54a0e447255d37665aae07750f368)) +* Update from Structify backend changes ([9c85788](https://github.com/StructifyAI/structify-python/commit/9c8578843117aabfed6c177eef54dd55b32153d4)) +* Update from Structify backend changes ([7300ef1](https://github.com/StructifyAI/structify-python/commit/7300ef146472dae2bc013c407e3dc21806adb8ba)) +* Update from Structify backend changes ([9ccbf40](https://github.com/StructifyAI/structify-python/commit/9ccbf40f09c05630249647b7f4a24ee75de96159)) +* Update from Structify backend changes ([856162a](https://github.com/StructifyAI/structify-python/commit/856162a9e8724dda056be17cf39157a3a2d2b733)) +* Update from Structify backend changes ([0135605](https://github.com/StructifyAI/structify-python/commit/01356050e6b8ca81b73063513a3620830ce2d84f)) +* Update from Structify backend changes ([cb2bde3](https://github.com/StructifyAI/structify-python/commit/cb2bde357153c0bc2d0b145868e0d62915f4f952)) +* Update from Structify backend changes ([a1eb77b](https://github.com/StructifyAI/structify-python/commit/a1eb77bd78add7544ae5bc0d72535d317ee23098)) +* Update from Structify backend changes ([bde5a39](https://github.com/StructifyAI/structify-python/commit/bde5a390b285b282578bb6b4857285b2abd23491)) +* Update from Structify backend changes ([ca4fa72](https://github.com/StructifyAI/structify-python/commit/ca4fa72263d7eb09ba0aa91e2d0e32b1d724bbc1)) +* Update from Structify backend changes ([37cd67f](https://github.com/StructifyAI/structify-python/commit/37cd67f7a018a7d6b37aea2646ca1f9d5559977d)) +* Update from Structify backend changes ([387dd18](https://github.com/StructifyAI/structify-python/commit/387dd1845dfe380e4f36dfa592b57e3131f76fed)) +* Update from Structify backend changes ([d31cd4b](https://github.com/StructifyAI/structify-python/commit/d31cd4b98af129060626b47828b9d99dfae6dbce)) +* Update from Structify backend changes ([da0f0de](https://github.com/StructifyAI/structify-python/commit/da0f0de6d612197df5fd6c85d493e25474f71f1b)) +* Update from Structify backend changes ([2db1ef6](https://github.com/StructifyAI/structify-python/commit/2db1ef601ecc67ffb5696f4cf8cdd6e92e8915bf)) +* Update from Structify backend changes ([ac9f0d5](https://github.com/StructifyAI/structify-python/commit/ac9f0d53b217e035ccbb75d026593634e054f117)) +* Update from Structify backend changes ([5a23230](https://github.com/StructifyAI/structify-python/commit/5a232300a64a4d64671f8167da883d3b80389b9b)) +* Update from Structify backend changes ([234176c](https://github.com/StructifyAI/structify-python/commit/234176cb1e424b08de929ee3445ab3ccf6c85105)) +* Update from Structify backend changes ([9586986](https://github.com/StructifyAI/structify-python/commit/9586986c012ee305ab90de33c7d74ea715becee2)) +* Update from Structify backend changes ([4ec4f4f](https://github.com/StructifyAI/structify-python/commit/4ec4f4f2c97687d23575d9b235ee1a3aefef648d)) +* Update from Structify backend changes ([9c9b785](https://github.com/StructifyAI/structify-python/commit/9c9b785cb118b656322d0614e6602b1f64f25c9b)) +* Update from Structify backend changes ([0175b62](https://github.com/StructifyAI/structify-python/commit/0175b62731b9c9e7cc3a2069b32ed44fae801df2)) +* Update from Structify backend changes ([e8fa6c0](https://github.com/StructifyAI/structify-python/commit/e8fa6c0eee8eef620bd297933c4bbff1da13b798)) +* Update from Structify backend changes ([2d67a15](https://github.com/StructifyAI/structify-python/commit/2d67a154e0b37a1a29e35e21678b059a8cfe1e85)) +* Update from Structify backend changes ([aa26452](https://github.com/StructifyAI/structify-python/commit/aa264524de4459f4977103f5884778d5b3e5200f)) +* Update from Structify backend changes ([6cdb36b](https://github.com/StructifyAI/structify-python/commit/6cdb36ba947a077d7a4ea24ec416da65d2cf4c3f)) +* Update from Structify backend changes ([20ef4cf](https://github.com/StructifyAI/structify-python/commit/20ef4cf65fbf656dec67a065725fc4931a224912)) +* Update from Structify backend changes ([38e454b](https://github.com/StructifyAI/structify-python/commit/38e454b00abe1dbd46adcbcf73e01f0babae4faa)) +* Update from Structify backend changes ([74d1ead](https://github.com/StructifyAI/structify-python/commit/74d1eadcaade7a9bf4f43a968b34a69441647b47)) +* Update from Structify backend changes ([9f87667](https://github.com/StructifyAI/structify-python/commit/9f876676e531c57f0133d2a413bf739d3f7f93cc)) +* Update from Structify backend changes ([e348c2a](https://github.com/StructifyAI/structify-python/commit/e348c2a7b58b48e7c5655757a098bea70033b2b9)) +* Update from Structify backend changes ([c4ccd37](https://github.com/StructifyAI/structify-python/commit/c4ccd37bdf1803dfceb77762fb2c50a960ec4e27)) +* Update from Structify backend changes ([4148cb4](https://github.com/StructifyAI/structify-python/commit/4148cb4b20cbe6cf0ca8371d0d4c602a80f5a764)) +* Update from Structify backend changes ([3536c2c](https://github.com/StructifyAI/structify-python/commit/3536c2cb1daa0eadb86d4966210d1a4bbe45c2c9)) +* Update from Structify backend changes ([95228ad](https://github.com/StructifyAI/structify-python/commit/95228adc1fd74e0ebec420fabceed3d133c2f7be)) +* Update from Structify backend changes ([1df1a86](https://github.com/StructifyAI/structify-python/commit/1df1a867e1490126f24a42ad3c2e16cdc485e92d)) +* Update from Structify backend changes ([59a5760](https://github.com/StructifyAI/structify-python/commit/59a57607f5c573af3639642bfaa20b8bd59f2f8d)) +* Update from Structify backend changes ([761ede8](https://github.com/StructifyAI/structify-python/commit/761ede84e233b966e824ac0aba9bc27b73567f48)) +* Update from Structify backend changes ([bb8b31f](https://github.com/StructifyAI/structify-python/commit/bb8b31f20614a17e816c2ba850429eb0ed71650e)) +* Update from Structify backend changes ([e6f9de0](https://github.com/StructifyAI/structify-python/commit/e6f9de054fb1e15331baa2949f171b9284e83690)) +* Update from Structify backend changes ([74b1b21](https://github.com/StructifyAI/structify-python/commit/74b1b217602570cb51c926fb93057318b4e63a81)) +* Update from Structify backend changes ([27ab73d](https://github.com/StructifyAI/structify-python/commit/27ab73d19b4c16c19c1b95015d3a10cd4d9bd58f)) +* Update from Structify backend changes ([003a774](https://github.com/StructifyAI/structify-python/commit/003a774cb8dd043eda2b550b00acdb9e9e3b5a64)) +* Update from Structify backend changes ([37cc1d9](https://github.com/StructifyAI/structify-python/commit/37cc1d9c7a286de5680f51b9f97125d824022cf1)) +* Update from Structify backend changes ([1e163ca](https://github.com/StructifyAI/structify-python/commit/1e163ca21cb69ea540293df7fa86a2edd74b9c6a)) +* Update from Structify backend changes ([f0e673a](https://github.com/StructifyAI/structify-python/commit/f0e673a1faeef8766e2a3d315c13efea2e1e27fd)) +* Update from Structify backend changes ([06905d3](https://github.com/StructifyAI/structify-python/commit/06905d33be13a97cb80f22d04354695456429e7f)) +* Update from Structify backend changes ([7b2a30a](https://github.com/StructifyAI/structify-python/commit/7b2a30a861fb15068c26b16f4dc6f8fc9de7a59c)) +* Update from Structify backend changes ([11b106e](https://github.com/StructifyAI/structify-python/commit/11b106e4ed0d8d8990206878d403f3462f244b67)) +* Update from Structify backend changes ([657d6aa](https://github.com/StructifyAI/structify-python/commit/657d6aae3f7758ec809f7e41a7805405dfe617b7)) +* Update from Structify backend changes ([e3ad58e](https://github.com/StructifyAI/structify-python/commit/e3ad58e6c063c306aa5e481ec97c74cf4e3ba313)) +* Update from Structify backend changes ([8be62b6](https://github.com/StructifyAI/structify-python/commit/8be62b67db9556a1a8dbd7f7cc5080ae2e164cde)) +* Update from Structify backend changes ([46fc19d](https://github.com/StructifyAI/structify-python/commit/46fc19ded10bfac99a76d2c3a4a3f08d271c25e5)) +* Update from Structify backend changes ([06d6f58](https://github.com/StructifyAI/structify-python/commit/06d6f5872b86da5de923d0657b0c340f312d42ec)) +* Update from Structify backend changes ([d28fc51](https://github.com/StructifyAI/structify-python/commit/d28fc512323f5c7eecd56e086a6894c4e2ea2794)) +* Update from Structify backend changes ([3e01edf](https://github.com/StructifyAI/structify-python/commit/3e01edfbfeb5703f1e52a8d5fd7d7825a49adec3)) +* Update from Structify backend changes ([ffda5ed](https://github.com/StructifyAI/structify-python/commit/ffda5ed618ac602e2e9287512f4b0876c421d741)) +* Update from Structify backend changes ([ef67e88](https://github.com/StructifyAI/structify-python/commit/ef67e8857e56940b6d8f7b7d351ce8bf6d2d6d29)) +* Update from Structify backend changes ([6f8c059](https://github.com/StructifyAI/structify-python/commit/6f8c059edc0ed2a5fb61c805f3a28ece6397f207)) +* Update from Structify backend changes ([ab6c580](https://github.com/StructifyAI/structify-python/commit/ab6c580596d6cb790650173533f43d647651e25a)) +* Update from Structify backend changes ([9091cce](https://github.com/StructifyAI/structify-python/commit/9091cce1f24daa6ec1079c5b313a8c212173f835)) +* Update from Structify backend changes ([fdc379a](https://github.com/StructifyAI/structify-python/commit/fdc379a0fbc2ecc263f473553bded63e671a5640)) +* Update from Structify backend changes ([68e0e5a](https://github.com/StructifyAI/structify-python/commit/68e0e5a43037252590cf8a697d4b78760c4a7260)) +* Update from Structify backend changes ([7822818](https://github.com/StructifyAI/structify-python/commit/782281890bbcb0117c542df7072e167a4b978a1d)) +* Update from Structify backend changes ([5c40f7b](https://github.com/StructifyAI/structify-python/commit/5c40f7b6977787dee2e1d96b1b13a4379229f38a)) +* Update from Structify backend changes ([6cbcd7d](https://github.com/StructifyAI/structify-python/commit/6cbcd7d9e1c0374a9d6780e44f107ba37bea8d4f)) +* Update from Structify backend changes ([f733d2a](https://github.com/StructifyAI/structify-python/commit/f733d2aad89b62c283d279a02d341d2b05a6357e)) +* Update from Structify backend changes ([6c64d5c](https://github.com/StructifyAI/structify-python/commit/6c64d5c8b902b82ef046fafbef03dfbe27fbd05c)) +* Update from Structify backend changes ([454d1dd](https://github.com/StructifyAI/structify-python/commit/454d1ddd7f12b025bb552850da43d381f702fb55)) +* Update from Structify backend changes ([04eadec](https://github.com/StructifyAI/structify-python/commit/04eadec50e082e5ce788917a4d7a7e916c4a6765)) +* Update from Structify backend changes ([248cbcb](https://github.com/StructifyAI/structify-python/commit/248cbcb0cb64809d62173317c07498ad37cd83d2)) +* Update from Structify backend changes ([dade595](https://github.com/StructifyAI/structify-python/commit/dade59552964ae2200022f60dc64f17543d225d3)) +* Update from Structify backend changes ([4c65bf1](https://github.com/StructifyAI/structify-python/commit/4c65bf113a5aeada0e0fa77d46c5cacf50632e7a)) + + +### Bug Fixes + +* **deps:** bump minimum typing-extensions version ([e948f17](https://github.com/StructifyAI/structify-python/commit/e948f171a34d73a5b6e5f6b334a86b6b98180d4d)) +* **pydantic:** do not pass `by_alias` unless set ([ea00e09](https://github.com/StructifyAI/structify-python/commit/ea00e09a4b072323f1f13c2825773257f638c462)) +* sanitize endpoint path params ([dd440d0](https://github.com/StructifyAI/structify-python/commit/dd440d04c277fee4e8373c09bc51b43a951369a1)) + + +### Chores + +* **ci:** skip lint on metadata-only changes ([a9b43a6](https://github.com/StructifyAI/structify-python/commit/a9b43a66365028af38669fe38d6a6275e70980c0)) +* **ci:** skip uploading artifacts on stainless-internal branches ([e426d6b](https://github.com/StructifyAI/structify-python/commit/e426d6bf94f57c72581cd3289faf17a8dcd4538e)) +* format all `api.md` files ([fc8a112](https://github.com/StructifyAI/structify-python/commit/fc8a112722cb379d824920e3fde59345fdb4df85)) +* **internal:** add request options to SSE classes ([aa6dc7f](https://github.com/StructifyAI/structify-python/commit/aa6dc7fc0ef92720834578efa70fc6661b4b69a8)) +* **internal:** codegen related update ([206ea94](https://github.com/StructifyAI/structify-python/commit/206ea94f15ea80ed61eca73e32ef753a57b2ede7)) +* **internal:** fix lint error on Python 3.14 ([3a7173f](https://github.com/StructifyAI/structify-python/commit/3a7173f56434bada6297dc0b2b25cd77fa0053cb)) +* **internal:** make `test_proxy_environment_variables` more resilient ([3543b8f](https://github.com/StructifyAI/structify-python/commit/3543b8f5f16df6c661e561ecb5d01d5959fc0f72)) +* **internal:** make `test_proxy_environment_variables` more resilient to env ([42b68e8](https://github.com/StructifyAI/structify-python/commit/42b68e89e75ab91d86ee3b492c2a648acd338ad6)) +* **internal:** tweak CI branches ([92ed8ac](https://github.com/StructifyAI/structify-python/commit/92ed8ac799e16266310bc9e66cb8bbcff3e681aa)) +* **internal:** update gitignore ([60f8dcd](https://github.com/StructifyAI/structify-python/commit/60f8dcd5ac4811c83554ec663bd4d457f33539a5)) +* **test:** do not count install time for mock server timeout ([1563f48](https://github.com/StructifyAI/structify-python/commit/1563f48901ebd6545e8eb594370b12019fb47a30)) +* **tests:** bump steady to v0.19.4 ([15d506e](https://github.com/StructifyAI/structify-python/commit/15d506ee5ea1a4a7bf1a0091237718e1f94edad9)) +* **tests:** bump steady to v0.19.5 ([afa480c](https://github.com/StructifyAI/structify-python/commit/afa480c9b5df39ee202220baf8a7dbf7a367eb39)) +* **tests:** bump steady to v0.19.6 ([4dd5324](https://github.com/StructifyAI/structify-python/commit/4dd53245dca023dac6911d512963d2a14b0155b7)) +* **tests:** bump steady to v0.19.7 ([dc20757](https://github.com/StructifyAI/structify-python/commit/dc20757e4e4ae8250f8468084bc71e638238519c)) +* update mock server docs ([c7ba1b2](https://github.com/StructifyAI/structify-python/commit/c7ba1b2e113db5b1df0282216045997064362d93)) +* update placeholder string ([cfb1da4](https://github.com/StructifyAI/structify-python/commit/cfb1da44851a3714a7096d23413a09abae1ecfc5)) + + +### Refactors + +* **tests:** switch from prism to steady ([cc504ac](https://github.com/StructifyAI/structify-python/commit/cc504acffcde1581af4c46f697b06ff34dfb4643)) + ## 1.183.0 (2026-02-11) Full Changelog: [v1.182.0...v1.183.0](https://github.com/StructifyAI/structify-python/compare/v1.182.0...v1.183.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 15492f27f..cdb270a71 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,11 +85,10 @@ $ pip install ./path-to-wheel-file.whl ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh diff --git a/README.md b/README.md index 7c3467649..2a8ad2bb6 100644 --- a/README.md +++ b/README.md @@ -120,12 +120,12 @@ from structify import Structify client = Structify() -all_teams = [] +all_jobs = [] # Automatically fetches more pages as needed. -for team in client.admin.teams.list(): - # Do something with team here - all_teams.append(team) -print(all_teams) +for job in client.admin.jobs.list(): + # Do something with job here + all_jobs.append(job) +print(all_jobs) ``` Or, asynchronously: @@ -138,11 +138,11 @@ client = AsyncStructify() async def main() -> None: - all_teams = [] + all_jobs = [] # Iterate through items across all pages, issuing requests as needed. - async for team in client.admin.teams.list(): - all_teams.append(team) - print(all_teams) + async for job in client.admin.jobs.list(): + all_jobs.append(job) + print(all_jobs) asyncio.run(main()) @@ -151,7 +151,7 @@ asyncio.run(main()) Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: ```python -first_page = await client.admin.teams.list() +first_page = await client.admin.jobs.list() if first_page.has_next_page(): print(f"will fetch next page using these details: {first_page.next_page_info()}") next_page = await first_page.get_next_page() @@ -163,9 +163,9 @@ if first_page.has_next_page(): Or just work directly with the returned data: ```python -first_page = await client.admin.teams.list() -for team in first_page.items: - print(team) +first_page = await client.admin.jobs.list() +for job in first_page.items: + print(job.id) # Remove `await` for non-async usage. ``` @@ -195,10 +195,11 @@ from structify import Structify client = Structify() -client.documents.upload( +client.chat.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", content=Path("/path/to/file"), - file_type="Text", - path=b"raw file contents", + content_type="content_type", + file_name="file_name", ) ``` diff --git a/api.md b/api.md index b4715b28a..7bf8b004d 100644 --- a/api.md +++ b/api.md @@ -19,9 +19,13 @@ Types: ```python from structify.types import ( EnrichUserParams, + GetOnboardingAnswersResponse, JwtToAPITokenRequest, + OnboardingAnswers, RefreshSessionRequest, RefreshSessionResponse, + SaveOnboardingAnswersRequest, + SaveOnboardingAnswersResponse, SurveySubmissionRequest, SurveySubmissionResponse, TokenResponse, @@ -36,8 +40,10 @@ Methods: - client.user.update(\*\*params) -> User - client.user.enrich(\*\*params) -> None +- client.user.get_onboarding_answers() -> GetOnboardingAnswersResponse - client.user.info() -> UserInfo - client.user.refresh(\*\*params) -> RefreshSessionResponse +- client.user.save_onboarding_answers(\*\*params) -> SaveOnboardingAnswersResponse - client.user.survey_submit(\*\*params) -> SurveySubmissionResponse - client.user.transactions() -> UserTransactionsResponse - client.user.usage(\*\*params) -> UserUsageResponse @@ -100,9 +106,11 @@ from structify.types import ( ChatSessionWithMessages, ChatTemplate, ChatVisibility, + CompressChatResponse, CopyChatSessionRequest, CreateChatSessionRequest, CreateChatSessionResponse, + DashboardItem, DeleteChatSessionResponse, ErrorResponse, GetChatSessionResponse, @@ -110,7 +118,11 @@ from structify.types import ( GrantAdminAccessRequest, ListChatSessionsResponse, ListCollaboratorsResponse, + ListDashboardsResponse, Message, + SimulatePromptRequest, + SimulatePromptResponse, + TemplateQuestion, ToolInvocation, ToolResult, UpdateChatSessionFavoriteRequest, @@ -119,13 +131,16 @@ from structify.types import ( UpdateVisibilityResponse, ChatAddGitCommitResponse, ChatCopyNodeOutputByCodeHashResponse, - ChatDeleteFilesResponse, + ChatDeleteInputFileResponse, ChatGetGitCommitResponse, ChatGetPartialChatsResponse, ChatGetSessionTimelineResponse, + ChatListInputFilesResponse, ChatListTemplatesResponse, ChatLoadFilesResponse, + ChatLoadInputFilesResponse, ChatRevertToCommitResponse, + ChatUploadInputFileResponse, ) ``` @@ -133,29 +148,36 @@ Methods: - client.chat.add_collaborator(chat_id, \*\*params) -> None - client.chat.add_git_commit(session_id, \*\*params) -> ChatAddGitCommitResponse -- client.chat.admin_get_chat_prompt(session_id) -> ChatPrompt - client.chat.admin_issue_found(chat_id, \*\*params) -> AdminIssueFoundResponse +- client.chat.compress(session_id) -> CompressChatResponse - client.chat.copy(\*\*params) -> ChatSessionWithMessages -- client.chat.copy_node_output_by_code_hash(session_id, \*\*params) -> str +- client.chat.copy_node_output_by_code_hash(session_id, \*\*params) -> ChatCopyNodeOutputByCodeHashResponse - client.chat.create_session(\*\*params) -> CreateChatSessionResponse -- client.chat.delete_files(chat_id, \*\*params) -> ChatDeleteFilesResponse +- client.chat.delete_input_file(chat_id, \*\*params) -> ChatDeleteInputFileResponse - client.chat.delete_session(session_id) -> DeleteChatSessionResponse - client.chat.get_dependencies(session_id) -> GetDependenciesResponse - client.chat.get_git_commit(commit_hash, \*, chat_id) -> ChatGetGitCommitResponse - client.chat.get_partial_chats(chat_session_id) -> ChatGetPartialChatsResponse - client.chat.get_session(session_id) -> GetChatSessionResponse - client.chat.get_session_timeline(session_id) -> ChatGetSessionTimelineResponse +- client.chat.get_template(template_id) -> ChatTemplate - client.chat.grant_admin_override(chat_id, \*\*params) -> AdminGrantAccessResponse - client.chat.list_collaborators(chat_id) -> ListCollaboratorsResponse +- client.chat.list_dashboards(chat_id, \*\*params) -> ListDashboardsResponse +- client.chat.list_input_files(chat_id) -> ChatListInputFilesResponse - client.chat.list_sessions(\*\*params) -> ListChatSessionsResponse - client.chat.list_templates() -> ChatListTemplatesResponse - client.chat.load_files(\*\*params) -> ChatLoadFilesResponse +- client.chat.load_input_file(filename, \*, chat_id) -> BinaryAPIResponse +- client.chat.load_input_files(chat_id, \*\*params) -> ChatLoadInputFilesResponse - client.chat.make_permanent(session_id) -> None - client.chat.remove_collaborator(user_id, \*, chat_id) -> None - client.chat.revert_to_commit(session_id, \*\*params) -> ChatRevertToCommitResponse +- client.chat.simulate_prompt(chat_session_id, \*\*params) -> SimulatePromptResponse - client.chat.update_session(session_id, \*\*params) -> ChatSession - client.chat.update_session_favorite(session_id, \*\*params) -> ChatSession - client.chat.update_visibility(session_id, \*\*params) -> UpdateVisibilityResponse +- client.chat.upload_input_file(chat_id, \*\*params) -> ChatUploadInputFileResponse # Teams @@ -258,6 +280,16 @@ Methods: # Admin +Types: + +```python +from structify.types import ReportCriticalRequest +``` + +Methods: + +- client.admin.report_critical(\*\*params) -> None + ## Teams Types: @@ -282,12 +314,13 @@ from structify.types.admin import ( GrantCreditsResponse, UpdateSeatsOverrideRequest, UpdateSeatsOverrideResponse, + TeamListResponse, ) ``` Methods: -- client.admin.teams.list(\*\*params) -> SyncJobsList[AdminTeamsListResponse] +- client.admin.teams.list(\*\*params) -> TeamListResponse - client.admin.teams.add_member(\*\*params) -> AdminAddMemberResponse - client.admin.teams.cancel_subscription(\*\*params) -> CancelSubscriptionResponse - client.admin.teams.create_subscription(\*\*params) -> CreateSubscriptionResponse @@ -319,14 +352,22 @@ from structify.types.admin import ( AdminDeleteJobsRequest, AdminDeleteJobsResponse, AdminListJobsRequestParams, - AdminListJobsResponse, + JobListResponse, + JobConcurrencyResponse, + JobKillByUserResponse, + JobRunningStatsResponse, + JobUpdateConcurrencyResponse, ) ``` Methods: -- client.admin.jobs.list(\*\*params) -> SyncJobsList[AdminListJobsResponse] +- client.admin.jobs.list(\*\*params) -> SyncJobsList[JobListResponse] - client.admin.jobs.delete(\*\*params) -> AdminDeleteJobsResponse +- client.admin.jobs.concurrency() -> JobConcurrencyResponse +- client.admin.jobs.kill_by_user(\*\*params) -> JobKillByUserResponse +- client.admin.jobs.running_stats() -> JobRunningStatsResponse +- client.admin.jobs.update_concurrency(\*\*params) -> JobUpdateConcurrencyResponse ## Sandbox @@ -406,15 +447,21 @@ Types: ```python from structify.types.admin import ( + AdminListConnectorsResponse, CloneConnectorItem, CloneConnectorsRequest, - CloneConnectorsResponse, + DatahubIngestionKey, + DatahubIngestionType, + SetDatahubConfigRequest, + ConnectorCloneResponse, ) ``` Methods: -- client.admin.connector.clone(\*\*params) -> CloneConnectorsResponse +- client.admin.connector.clone(\*\*params) -> ConnectorCloneResponse +- client.admin.connector.list_team_connectors(team_id) -> AdminListConnectorsResponse +- client.admin.connector.set_datahub_config(\*\*params) -> Connector # Datasets @@ -503,8 +550,7 @@ from structify.types import ( GetJobEventsResponse, JobListResponse, JobCancelResponse, - JobGetScrapersResponse, - JobGetSourceEntitiesResponse, + JobGetResponse, JobStatusResponse, ) ``` @@ -513,9 +559,8 @@ Methods: - client.jobs.list(\*\*params) -> SyncJobsList[JobListResponse] - client.jobs.cancel(uuid) -> JobCancelResponse +- client.jobs.get(job_id) -> JobGetResponse - client.jobs.get_events(job_id) -> GetJobEventsResponse -- client.jobs.get_scrapers(job_id) -> JobGetScrapersResponse -- client.jobs.get_source_entities(job_id) -> JobGetSourceEntitiesResponse - client.jobs.schedule() -> None - client.jobs.status(\*\*params) -> JobStatusResponse @@ -550,6 +595,7 @@ from structify.types import ( Dashboard, DashboardComponent, DashboardPage, + DashboardSpec, EdgeSpec, EditNodeOutputRequest, FinalizeDagRequest, @@ -561,11 +607,27 @@ from structify.types import ( NodeSpec, ParquetEdit, RequestConfirmationRequest, + TriggerReviewResponse, UpdateWorkflowNodeProgressRequest, UpdateWorkflowNodeRequest, UploadDashboardLayoutRequest, UploadNodeVisualizationOutputRequest, + VizBooleanControl, + VizBooleanControlType, + VizControlOption, + VizDateControl, + VizDateControlType, + VizFigure, + VizFigureDefinition, + VizFigureKind, + VizNumberControl, + VizNumberControlType, + VizParam, + VizQuery, + VizStringControl, + VizStringControlType, WorkflowDag, + WorkflowDashboardItem, WorkflowNodeExecutionStatus, WorkflowNodeLog, WorkflowSession, @@ -593,6 +655,7 @@ Methods: - client.sessions.kill_jobs(session_id, \*\*params) -> SessionKillJobsResponse - client.sessions.mark_errored(session_id, \*\*params) -> WorkflowSession - client.sessions.request_confirmation(node_id, \*\*params) -> WorkflowSessionNode +- client.sessions.trigger_review(session_id) -> TriggerReviewResponse - client.sessions.update_node(node_id, \*\*params) -> WorkflowSessionNode - client.sessions.update_node_progress(node_id, \*\*params) -> WorkflowSessionNode - client.sessions.upload_dashboard_layout(session_id, \*\*params) -> WorkflowSession @@ -651,29 +714,35 @@ from structify.types import ( ConnectorSummariesRequest, ConnectorSummary, ConnectorTableInfo, + ConnectorTablePathResponse, ConnectorWithSecrets, ConnectorWithSnippets, CreateConnectorRequest, CreateSecretRequest, + DatahubProgress, + DatahubSecretMap, DeleteSchemaObjectRequest, DeleteSchemaObjectResponse, ExplorationPhaseID, + ExplorationProgress, ExplorationRun, ExplorationRunsResponse, ExplorationStatus, ExploreConnectorRequest, - ExploreStatusResponse, ExplorerChatResponse, ListTablesResponse, LlmInformationStore, + PhaseActivity, SchemaObjectID, UpdateColumnRequest, UpdateConnectorRequest, UpdateTableRequest, UpdateTableResponse, ConnectorAddSchemaObjectResponse, + ConnectorExploreResponse, ConnectorGetResponse, ConnectorGetClarificationRequestsResponse, + ConnectorListStoresResponse, ConnectorListWithSnippetsResponse, ConnectorSearchTablesResponse, ConnectorSummariesResponse, @@ -690,20 +759,25 @@ Methods: - client.connectors.create_secret(connector_id, \*\*params) -> None - client.connectors.delete_schema_object(connector_id, \*\*params) -> DeleteSchemaObjectResponse - client.connectors.delete_secret(secret_name, \*, connector_id) -> None -- client.connectors.explore(connector_id, \*\*params) -> None +- client.connectors.download_datahub_artifact(kind, \*, connector_id, \*\*params) -> BinaryAPIResponse +- client.connectors.explore(connector_id, \*\*params) -> ConnectorExploreResponse - client.connectors.get(connector_id) -> ConnectorGetResponse +- client.connectors.get_active_exploration_run(connector_id) -> Optional[ExplorationRun] - client.connectors.get_clarification_requests(connector_id) -> ConnectorGetClarificationRequestsResponse +- client.connectors.get_exploration_run_progress(run_id, \*, connector_id) -> ExplorationProgress - client.connectors.get_exploration_runs(connector_id) -> ExplorationRunsResponse -- client.connectors.get_exploration_status(connector_id) -> ExploreStatusResponse - client.connectors.get_explorer_chat(connector_id, \*\*params) -> ExplorerChatResponse - client.connectors.get_store(connector_id) -> ConnectorStoreResponse +- client.connectors.get_table_path(table_id) -> ConnectorTablePathResponse +- client.connectors.list_stores() -> ConnectorListStoresResponse - client.connectors.list_tables(connector_id) -> ListTablesResponse -- client.connectors.list_with_snippets(\*\*params) -> ConnectorListWithSnippetsResponse +- client.connectors.list_with_snippets() -> ConnectorListWithSnippetsResponse - client.connectors.resolve_clarification(clarification_id) -> None - client.connectors.search_tables(\*\*params) -> ConnectorSearchTablesResponse - client.connectors.summaries(\*\*params) -> ConnectorSummariesResponse - client.connectors.update_column(column_id, \*\*params) -> None - client.connectors.update_table(table_id, \*\*params) -> UpdateTableResponse +- client.connectors.upload_datahub_artifact(kind, \*, connector_id, \*\*params) -> None ## TypeSnippets @@ -870,13 +944,19 @@ Methods: Types: ```python -from structify.types import GetSandboxRequest, Sandbox, SandboxListResponse +from structify.types import ( + GetSandboxRequest, + Sandbox, + SandboxListResponse, + SandboxGetMetricsResponse, +) ``` Methods: - client.sandbox.list(chat_id) -> SandboxListResponse - client.sandbox.get(chat_id, \*\*params) -> Sandbox +- client.sandbox.get_metrics(sandbox_id) -> SandboxGetMetricsResponse - client.sandbox.update_status(sandbox_id, \*\*params) -> Sandbox # Scrape @@ -902,11 +982,12 @@ Methods: Types: ```python -from structify.types import GenerateCodeRequest, InterruptGenerationRequest +from structify.types import ApplyManualEditRequest, GenerateCodeRequest, InterruptGenerationRequest ``` Methods: +- client.code.apply_manual_edit(chat_id, \*\*params) -> None - client.code.generate_code(\*\*params) -> None - client.code.interrupt_generation(\*\*params) -> None @@ -918,7 +999,6 @@ Types: from structify.types import ( ChatPrompt, SaveRequirement, - ToolMetadata, StructureEnhancePropertyResponse, StructureEnhanceRelationshipResponse, StructureFindRelationshipResponse, diff --git a/pyproject.toml b/pyproject.toml index e1c617e27..ba360bd07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "structifyai" -version = "1.183.0" +version = "1.184.0" description = "The official Python library for the structify API" dynamic = ["readme"] license = "Apache-2.0" @@ -11,11 +11,12 @@ authors = [ dependencies = [ "httpx>=0.23.0, <1", "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", + "typing-extensions>=4.14, <5", "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", "polars==1.31.0", + "pypdf>=4.0.0,<5.0.0", "tqdm>=4.66.2,<4.67.0", ] @@ -72,7 +73,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ diff --git a/scripts/mock b/scripts/mock index 0b28f6ea2..290e21b9a 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,23 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stdy/cli@0.19.7 -- steady --version - # Wait for server to come online + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=0 + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Steady server to start" + cat .stdy.log + exit 1 + fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index dbeda2d21..661f9bf48 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi diff --git a/src/structify/_client.py b/src/structify/_client.py index 76bd5e434..213456c0c 100644 --- a/src/structify/_client.py +++ b/src/structify/_client.py @@ -192,6 +192,7 @@ def __init__( @cached_property def whitelabel(self) -> WhitelabelResource: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import WhitelabelResource return WhitelabelResource(self) @@ -216,6 +217,7 @@ def teams(self) -> TeamsResource: @cached_property def wiki(self) -> WikiResource: + """Team wiki page management endpoints""" from .resources.wiki import WikiResource return WikiResource(self) @@ -228,18 +230,21 @@ def polars(self) -> PolarsResource: @cached_property def projects(self) -> ProjectsResource: + """Project management endpoints""" from .resources.projects import ProjectsResource return ProjectsResource(self) @cached_property def admin(self) -> AdminResource: + """Admin endpoints""" from .resources.admin import AdminResource return AdminResource(self) @cached_property def datasets(self) -> DatasetsResource: + """Dataset management endpoints""" from .resources.datasets import DatasetsResource return DatasetsResource(self) @@ -312,6 +317,7 @@ def entities(self) -> EntitiesResource: @cached_property def sandbox(self) -> SandboxResource: + """Sandbox management endpoints""" from .resources.sandbox import SandboxResource return SandboxResource(self) @@ -324,6 +330,7 @@ def scrape(self) -> ScrapeResource: @cached_property def code(self) -> CodeResource: + """Code generation endpoints""" from .resources.code import CodeResource return CodeResource(self) @@ -579,6 +586,7 @@ def __init__( @cached_property def whitelabel(self) -> AsyncWhitelabelResource: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import AsyncWhitelabelResource return AsyncWhitelabelResource(self) @@ -603,24 +611,28 @@ def teams(self) -> AsyncTeamsResource: @cached_property def wiki(self) -> AsyncWikiResource: + """Team wiki page management endpoints""" from .resources.wiki import AsyncWikiResource return AsyncWikiResource(self) @cached_property def projects(self) -> AsyncProjectsResource: + """Project management endpoints""" from .resources.projects import AsyncProjectsResource return AsyncProjectsResource(self) @cached_property def admin(self) -> AsyncAdminResource: + """Admin endpoints""" from .resources.admin import AsyncAdminResource return AsyncAdminResource(self) @cached_property def datasets(self) -> AsyncDatasetsResource: + """Dataset management endpoints""" from .resources.datasets import AsyncDatasetsResource return AsyncDatasetsResource(self) @@ -693,6 +705,7 @@ def entities(self) -> AsyncEntitiesResource: @cached_property def sandbox(self) -> AsyncSandboxResource: + """Sandbox management endpoints""" from .resources.sandbox import AsyncSandboxResource return AsyncSandboxResource(self) @@ -705,6 +718,7 @@ def scrape(self) -> AsyncScrapeResource: @cached_property def code(self) -> AsyncCodeResource: + """Code generation endpoints""" from .resources.code import AsyncCodeResource return AsyncCodeResource(self) @@ -883,6 +897,7 @@ def __init__(self, client: Structify) -> None: @cached_property def whitelabel(self) -> whitelabel.WhitelabelResourceWithRawResponse: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import WhitelabelResourceWithRawResponse return WhitelabelResourceWithRawResponse(self._client.whitelabel) @@ -907,12 +922,14 @@ def teams(self) -> teams.TeamsResourceWithRawResponse: @cached_property def wiki(self) -> wiki.WikiResourceWithRawResponse: + """Team wiki page management endpoints""" from .resources.wiki import WikiResourceWithRawResponse return WikiResourceWithRawResponse(self._client.wiki) @cached_property def projects(self) -> projects.ProjectsResourceWithRawResponse: + """Project management endpoints""" from .resources.projects import ProjectsResourceWithRawResponse return ProjectsResourceWithRawResponse(self._client.projects) @@ -925,12 +942,14 @@ def polars(self) -> polars.PolarsResourceWithRawResponse: @cached_property def admin(self) -> admin.AdminResourceWithRawResponse: + """Admin endpoints""" from .resources.admin import AdminResourceWithRawResponse return AdminResourceWithRawResponse(self._client.admin) @cached_property def datasets(self) -> datasets.DatasetsResourceWithRawResponse: + """Dataset management endpoints""" from .resources.datasets import DatasetsResourceWithRawResponse return DatasetsResourceWithRawResponse(self._client.datasets) @@ -1003,6 +1022,7 @@ def entities(self) -> entities.EntitiesResourceWithRawResponse: @cached_property def sandbox(self) -> sandbox.SandboxResourceWithRawResponse: + """Sandbox management endpoints""" from .resources.sandbox import SandboxResourceWithRawResponse return SandboxResourceWithRawResponse(self._client.sandbox) @@ -1015,6 +1035,7 @@ def scrape(self) -> scrape.ScrapeResourceWithRawResponse: @cached_property def code(self) -> code.CodeResourceWithRawResponse: + """Code generation endpoints""" from .resources.code import CodeResourceWithRawResponse return CodeResourceWithRawResponse(self._client.code) @@ -1052,6 +1073,7 @@ def __init__(self, client: AsyncStructify) -> None: @cached_property def whitelabel(self) -> whitelabel.AsyncWhitelabelResourceWithRawResponse: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import AsyncWhitelabelResourceWithRawResponse return AsyncWhitelabelResourceWithRawResponse(self._client.whitelabel) @@ -1076,24 +1098,28 @@ def teams(self) -> teams.AsyncTeamsResourceWithRawResponse: @cached_property def wiki(self) -> wiki.AsyncWikiResourceWithRawResponse: + """Team wiki page management endpoints""" from .resources.wiki import AsyncWikiResourceWithRawResponse return AsyncWikiResourceWithRawResponse(self._client.wiki) @cached_property def projects(self) -> projects.AsyncProjectsResourceWithRawResponse: + """Project management endpoints""" from .resources.projects import AsyncProjectsResourceWithRawResponse return AsyncProjectsResourceWithRawResponse(self._client.projects) @cached_property def admin(self) -> admin.AsyncAdminResourceWithRawResponse: + """Admin endpoints""" from .resources.admin import AsyncAdminResourceWithRawResponse return AsyncAdminResourceWithRawResponse(self._client.admin) @cached_property def datasets(self) -> datasets.AsyncDatasetsResourceWithRawResponse: + """Dataset management endpoints""" from .resources.datasets import AsyncDatasetsResourceWithRawResponse return AsyncDatasetsResourceWithRawResponse(self._client.datasets) @@ -1166,6 +1192,7 @@ def entities(self) -> entities.AsyncEntitiesResourceWithRawResponse: @cached_property def sandbox(self) -> sandbox.AsyncSandboxResourceWithRawResponse: + """Sandbox management endpoints""" from .resources.sandbox import AsyncSandboxResourceWithRawResponse return AsyncSandboxResourceWithRawResponse(self._client.sandbox) @@ -1178,6 +1205,7 @@ def scrape(self) -> scrape.AsyncScrapeResourceWithRawResponse: @cached_property def code(self) -> code.AsyncCodeResourceWithRawResponse: + """Code generation endpoints""" from .resources.code import AsyncCodeResourceWithRawResponse return AsyncCodeResourceWithRawResponse(self._client.code) @@ -1215,6 +1243,7 @@ def __init__(self, client: Structify) -> None: @cached_property def whitelabel(self) -> whitelabel.WhitelabelResourceWithStreamingResponse: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import WhitelabelResourceWithStreamingResponse return WhitelabelResourceWithStreamingResponse(self._client.whitelabel) @@ -1239,12 +1268,14 @@ def teams(self) -> teams.TeamsResourceWithStreamingResponse: @cached_property def wiki(self) -> wiki.WikiResourceWithStreamingResponse: + """Team wiki page management endpoints""" from .resources.wiki import WikiResourceWithStreamingResponse return WikiResourceWithStreamingResponse(self._client.wiki) @cached_property def projects(self) -> projects.ProjectsResourceWithStreamingResponse: + """Project management endpoints""" from .resources.projects import ProjectsResourceWithStreamingResponse return ProjectsResourceWithStreamingResponse(self._client.projects) @@ -1257,12 +1288,14 @@ def polars(self) -> polars.PolarsResourceWithStreamingResponse: @cached_property def admin(self) -> admin.AdminResourceWithStreamingResponse: + """Admin endpoints""" from .resources.admin import AdminResourceWithStreamingResponse return AdminResourceWithStreamingResponse(self._client.admin) @cached_property def datasets(self) -> datasets.DatasetsResourceWithStreamingResponse: + """Dataset management endpoints""" from .resources.datasets import DatasetsResourceWithStreamingResponse return DatasetsResourceWithStreamingResponse(self._client.datasets) @@ -1335,6 +1368,7 @@ def entities(self) -> entities.EntitiesResourceWithStreamingResponse: @cached_property def sandbox(self) -> sandbox.SandboxResourceWithStreamingResponse: + """Sandbox management endpoints""" from .resources.sandbox import SandboxResourceWithStreamingResponse return SandboxResourceWithStreamingResponse(self._client.sandbox) @@ -1347,6 +1381,7 @@ def scrape(self) -> scrape.ScrapeResourceWithStreamingResponse: @cached_property def code(self) -> code.CodeResourceWithStreamingResponse: + """Code generation endpoints""" from .resources.code import CodeResourceWithStreamingResponse return CodeResourceWithStreamingResponse(self._client.code) @@ -1384,6 +1419,7 @@ def __init__(self, client: AsyncStructify) -> None: @cached_property def whitelabel(self) -> whitelabel.AsyncWhitelabelResourceWithStreamingResponse: + """Whitelabeled service proxy endpoints""" from .resources.whitelabel import AsyncWhitelabelResourceWithStreamingResponse return AsyncWhitelabelResourceWithStreamingResponse(self._client.whitelabel) @@ -1408,24 +1444,28 @@ def teams(self) -> teams.AsyncTeamsResourceWithStreamingResponse: @cached_property def wiki(self) -> wiki.AsyncWikiResourceWithStreamingResponse: + """Team wiki page management endpoints""" from .resources.wiki import AsyncWikiResourceWithStreamingResponse return AsyncWikiResourceWithStreamingResponse(self._client.wiki) @cached_property def projects(self) -> projects.AsyncProjectsResourceWithStreamingResponse: + """Project management endpoints""" from .resources.projects import AsyncProjectsResourceWithStreamingResponse return AsyncProjectsResourceWithStreamingResponse(self._client.projects) @cached_property def admin(self) -> admin.AsyncAdminResourceWithStreamingResponse: + """Admin endpoints""" from .resources.admin import AsyncAdminResourceWithStreamingResponse return AsyncAdminResourceWithStreamingResponse(self._client.admin) @cached_property def datasets(self) -> datasets.AsyncDatasetsResourceWithStreamingResponse: + """Dataset management endpoints""" from .resources.datasets import AsyncDatasetsResourceWithStreamingResponse return AsyncDatasetsResourceWithStreamingResponse(self._client.datasets) @@ -1498,6 +1538,7 @@ def entities(self) -> entities.AsyncEntitiesResourceWithStreamingResponse: @cached_property def sandbox(self) -> sandbox.AsyncSandboxResourceWithStreamingResponse: + """Sandbox management endpoints""" from .resources.sandbox import AsyncSandboxResourceWithStreamingResponse return AsyncSandboxResourceWithStreamingResponse(self._client.sandbox) @@ -1510,6 +1551,7 @@ def scrape(self) -> scrape.AsyncScrapeResourceWithStreamingResponse: @cached_property def code(self) -> code.AsyncCodeResourceWithStreamingResponse: + """Code generation endpoints""" from .resources.code import AsyncCodeResourceWithStreamingResponse return AsyncCodeResourceWithStreamingResponse(self._client.code) diff --git a/src/structify/_compat.py b/src/structify/_compat.py index 786ff42ad..e6690a4f2 100644 --- a/src/structify/_compat.py +++ b/src/structify/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self, Literal +from typing_extensions import Self, Literal, TypedDict import pydantic from pydantic.fields import FieldInfo @@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: return model.model_dump_json(indent=indent) +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool + + def model_dump( model: pydantic.BaseModel, *, @@ -142,6 +146,9 @@ def model_dump( by_alias: bool | None = None, ) -> dict[str, Any]: if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias return model.model_dump( mode=mode, exclude=exclude, @@ -149,7 +156,7 @@ def model_dump( exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 warnings=True if PYDANTIC_V1 else warnings, - by_alias=by_alias, + **kwargs, ) return cast( "dict[str, Any]", diff --git a/src/structify/_qs.py b/src/structify/_qs.py index ada6fd3f7..de8c99bc6 100644 --- a/src/structify/_qs.py +++ b/src/structify/_qs.py @@ -101,7 +101,10 @@ def _stringify_item( items.extend(self._stringify_item(key, item, opts)) return items elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") + items = [] + for i, item in enumerate(value): + items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) + return items elif array_format == "brackets": items = [] key = key + "[]" diff --git a/src/structify/_response.py b/src/structify/_response.py index d9e6c9425..46c56282f 100644 --- a/src/structify/_response.py +++ b/src/structify/_response.py @@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/structify/_streaming.py b/src/structify/_streaming.py index 2eadb0067..da79cc765 100644 --- a/src/structify/_streaming.py +++ b/src/structify/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -13,6 +13,7 @@ if TYPE_CHECKING: from ._client import Structify, AsyncStructify + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -22,7 +23,7 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEBytesDecoder def __init__( @@ -31,10 +32,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: Structify, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -85,7 +88,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -94,10 +97,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncStructify, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() diff --git a/src/structify/_utils/__init__.py b/src/structify/_utils/__init__.py index dc64e29a1..10cb66d2d 100644 --- a/src/structify/_utils/__init__.py +++ b/src/structify/_utils/__init__.py @@ -1,3 +1,4 @@ +from ._path import path_template as path_template from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( diff --git a/src/structify/_utils/_compat.py b/src/structify/_utils/_compat.py index dd703233c..2c70b299c 100644 --- a/src/structify/_utils/_compat.py +++ b/src/structify/_utils/_compat.py @@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool: else: import types - return tp is Union or tp is types.UnionType + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] def is_typeddict(tp: Type[Any]) -> bool: diff --git a/src/structify/_utils/_path.py b/src/structify/_utils/_path.py new file mode 100644 index 000000000..4d6e1e4cb --- /dev/null +++ b/src/structify/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/structify/_version.py b/src/structify/_version.py index 8f1fc8183..cd8644a6c 100644 --- a/src/structify/_version.py +++ b/src/structify/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "structify" -__version__ = "1.183.0" # x-release-please-version +__version__ = "1.184.0" # x-release-please-version diff --git a/src/structify/resources/admin/admin.py b/src/structify/resources/admin/admin.py index 2f19ae99c..5b46c5a38 100644 --- a/src/structify/resources/admin/admin.py +++ b/src/structify/resources/admin/admin.py @@ -2,6 +2,8 @@ from __future__ import annotations +import httpx + from .jobs import ( JobsResource, AsyncJobsResource, @@ -26,6 +28,7 @@ UsersResourceWithStreamingResponse, AsyncUsersResourceWithStreamingResponse, ) +from ...types import admin_report_critical_params from .dataset import ( DatasetResource, AsyncDatasetResource, @@ -42,6 +45,8 @@ SandboxResourceWithStreamingResponse, AsyncSandboxResourceWithStreamingResponse, ) +from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from .connector import ( ConnectorResource, @@ -52,6 +57,13 @@ AsyncConnectorResourceWithStreamingResponse, ) 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 .chat_templates import ( ChatTemplatesResource, AsyncChatTemplatesResource, @@ -73,36 +85,46 @@ class AdminResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def teams(self) -> TeamsResource: + """Admin endpoints""" return TeamsResource(self._client) @cached_property def dataset(self) -> DatasetResource: + """Admin endpoints""" return DatasetResource(self._client) @cached_property def jobs(self) -> JobsResource: + """Admin endpoints""" return JobsResource(self._client) @cached_property def sandbox(self) -> SandboxResource: + """Admin endpoints""" return SandboxResource(self._client) @cached_property def functional_tests(self) -> FunctionalTestsResource: + """Admin endpoints""" return FunctionalTestsResource(self._client) @cached_property def users(self) -> UsersResource: + """Admin endpoints""" return UsersResource(self._client) @cached_property def chat_templates(self) -> ChatTemplatesResource: + """Admin endpoints""" return ChatTemplatesResource(self._client) @cached_property def connector(self) -> ConnectorResource: + """Admin endpoints""" return ConnectorResource(self._client) @cached_property @@ -124,38 +146,79 @@ def with_streaming_response(self) -> AdminResourceWithStreamingResponse: """ return AdminResourceWithStreamingResponse(self) + def report_critical( + self, + *, + message: 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, + ) -> None: + """ + 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 + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + "/admin/critical", + body=maybe_transform({"message": message}, admin_report_critical_params.AdminReportCriticalParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class AsyncAdminResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def teams(self) -> AsyncTeamsResource: + """Admin endpoints""" return AsyncTeamsResource(self._client) @cached_property def dataset(self) -> AsyncDatasetResource: + """Admin endpoints""" return AsyncDatasetResource(self._client) @cached_property def jobs(self) -> AsyncJobsResource: + """Admin endpoints""" return AsyncJobsResource(self._client) @cached_property def sandbox(self) -> AsyncSandboxResource: + """Admin endpoints""" return AsyncSandboxResource(self._client) @cached_property def functional_tests(self) -> AsyncFunctionalTestsResource: + """Admin endpoints""" return AsyncFunctionalTestsResource(self._client) @cached_property def users(self) -> AsyncUsersResource: + """Admin endpoints""" return AsyncUsersResource(self._client) @cached_property def chat_templates(self) -> AsyncChatTemplatesResource: + """Admin endpoints""" return AsyncChatTemplatesResource(self._client) @cached_property def connector(self) -> AsyncConnectorResource: + """Admin endpoints""" return AsyncConnectorResource(self._client) @cached_property @@ -177,41 +240,86 @@ def with_streaming_response(self) -> AsyncAdminResourceWithStreamingResponse: """ return AsyncAdminResourceWithStreamingResponse(self) + async def report_critical( + self, + *, + message: 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, + ) -> None: + """ + 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 + """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + "/admin/critical", + body=await async_maybe_transform( + {"message": message}, admin_report_critical_params.AdminReportCriticalParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + class AdminResourceWithRawResponse: def __init__(self, admin: AdminResource) -> None: self._admin = admin + self.report_critical = to_raw_response_wrapper( + admin.report_critical, + ) + @cached_property def teams(self) -> TeamsResourceWithRawResponse: + """Admin endpoints""" return TeamsResourceWithRawResponse(self._admin.teams) @cached_property def dataset(self) -> DatasetResourceWithRawResponse: + """Admin endpoints""" return DatasetResourceWithRawResponse(self._admin.dataset) @cached_property def jobs(self) -> JobsResourceWithRawResponse: + """Admin endpoints""" return JobsResourceWithRawResponse(self._admin.jobs) @cached_property def sandbox(self) -> SandboxResourceWithRawResponse: + """Admin endpoints""" return SandboxResourceWithRawResponse(self._admin.sandbox) @cached_property def functional_tests(self) -> FunctionalTestsResourceWithRawResponse: + """Admin endpoints""" return FunctionalTestsResourceWithRawResponse(self._admin.functional_tests) @cached_property def users(self) -> UsersResourceWithRawResponse: + """Admin endpoints""" return UsersResourceWithRawResponse(self._admin.users) @cached_property def chat_templates(self) -> ChatTemplatesResourceWithRawResponse: + """Admin endpoints""" return ChatTemplatesResourceWithRawResponse(self._admin.chat_templates) @cached_property def connector(self) -> ConnectorResourceWithRawResponse: + """Admin endpoints""" return ConnectorResourceWithRawResponse(self._admin.connector) @@ -219,36 +327,48 @@ class AsyncAdminResourceWithRawResponse: def __init__(self, admin: AsyncAdminResource) -> None: self._admin = admin + self.report_critical = async_to_raw_response_wrapper( + admin.report_critical, + ) + @cached_property def teams(self) -> AsyncTeamsResourceWithRawResponse: + """Admin endpoints""" return AsyncTeamsResourceWithRawResponse(self._admin.teams) @cached_property def dataset(self) -> AsyncDatasetResourceWithRawResponse: + """Admin endpoints""" return AsyncDatasetResourceWithRawResponse(self._admin.dataset) @cached_property def jobs(self) -> AsyncJobsResourceWithRawResponse: + """Admin endpoints""" return AsyncJobsResourceWithRawResponse(self._admin.jobs) @cached_property def sandbox(self) -> AsyncSandboxResourceWithRawResponse: + """Admin endpoints""" return AsyncSandboxResourceWithRawResponse(self._admin.sandbox) @cached_property def functional_tests(self) -> AsyncFunctionalTestsResourceWithRawResponse: + """Admin endpoints""" return AsyncFunctionalTestsResourceWithRawResponse(self._admin.functional_tests) @cached_property def users(self) -> AsyncUsersResourceWithRawResponse: + """Admin endpoints""" return AsyncUsersResourceWithRawResponse(self._admin.users) @cached_property def chat_templates(self) -> AsyncChatTemplatesResourceWithRawResponse: + """Admin endpoints""" return AsyncChatTemplatesResourceWithRawResponse(self._admin.chat_templates) @cached_property def connector(self) -> AsyncConnectorResourceWithRawResponse: + """Admin endpoints""" return AsyncConnectorResourceWithRawResponse(self._admin.connector) @@ -256,36 +376,48 @@ class AdminResourceWithStreamingResponse: def __init__(self, admin: AdminResource) -> None: self._admin = admin + self.report_critical = to_streamed_response_wrapper( + admin.report_critical, + ) + @cached_property def teams(self) -> TeamsResourceWithStreamingResponse: + """Admin endpoints""" return TeamsResourceWithStreamingResponse(self._admin.teams) @cached_property def dataset(self) -> DatasetResourceWithStreamingResponse: + """Admin endpoints""" return DatasetResourceWithStreamingResponse(self._admin.dataset) @cached_property def jobs(self) -> JobsResourceWithStreamingResponse: + """Admin endpoints""" return JobsResourceWithStreamingResponse(self._admin.jobs) @cached_property def sandbox(self) -> SandboxResourceWithStreamingResponse: + """Admin endpoints""" return SandboxResourceWithStreamingResponse(self._admin.sandbox) @cached_property def functional_tests(self) -> FunctionalTestsResourceWithStreamingResponse: + """Admin endpoints""" return FunctionalTestsResourceWithStreamingResponse(self._admin.functional_tests) @cached_property def users(self) -> UsersResourceWithStreamingResponse: + """Admin endpoints""" return UsersResourceWithStreamingResponse(self._admin.users) @cached_property def chat_templates(self) -> ChatTemplatesResourceWithStreamingResponse: + """Admin endpoints""" return ChatTemplatesResourceWithStreamingResponse(self._admin.chat_templates) @cached_property def connector(self) -> ConnectorResourceWithStreamingResponse: + """Admin endpoints""" return ConnectorResourceWithStreamingResponse(self._admin.connector) @@ -293,34 +425,46 @@ class AsyncAdminResourceWithStreamingResponse: def __init__(self, admin: AsyncAdminResource) -> None: self._admin = admin + self.report_critical = async_to_streamed_response_wrapper( + admin.report_critical, + ) + @cached_property def teams(self) -> AsyncTeamsResourceWithStreamingResponse: + """Admin endpoints""" return AsyncTeamsResourceWithStreamingResponse(self._admin.teams) @cached_property def dataset(self) -> AsyncDatasetResourceWithStreamingResponse: + """Admin endpoints""" return AsyncDatasetResourceWithStreamingResponse(self._admin.dataset) @cached_property def jobs(self) -> AsyncJobsResourceWithStreamingResponse: + """Admin endpoints""" return AsyncJobsResourceWithStreamingResponse(self._admin.jobs) @cached_property def sandbox(self) -> AsyncSandboxResourceWithStreamingResponse: + """Admin endpoints""" return AsyncSandboxResourceWithStreamingResponse(self._admin.sandbox) @cached_property def functional_tests(self) -> AsyncFunctionalTestsResourceWithStreamingResponse: + """Admin endpoints""" return AsyncFunctionalTestsResourceWithStreamingResponse(self._admin.functional_tests) @cached_property def users(self) -> AsyncUsersResourceWithStreamingResponse: + """Admin endpoints""" return AsyncUsersResourceWithStreamingResponse(self._admin.users) @cached_property def chat_templates(self) -> AsyncChatTemplatesResourceWithStreamingResponse: + """Admin endpoints""" return AsyncChatTemplatesResourceWithStreamingResponse(self._admin.chat_templates) @cached_property def connector(self) -> AsyncConnectorResourceWithStreamingResponse: + """Admin endpoints""" return AsyncConnectorResourceWithStreamingResponse(self._admin.connector) diff --git a/src/structify/resources/admin/chat_templates.py b/src/structify/resources/admin/chat_templates.py index 6ecc7daed..618e4344f 100644 --- a/src/structify/resources/admin/chat_templates.py +++ b/src/structify/resources/admin/chat_templates.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Optional +from typing import Iterable, Optional import httpx from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -19,12 +19,15 @@ from ...types.admin import chat_template_list_params, chat_template_create_params, chat_template_update_params from ..._base_client import make_request_options from ...types.chat_template import ChatTemplate +from ...types.template_question_param import TemplateQuestionParam from ...types.admin.chat_template_list_response import ChatTemplateListResponse __all__ = ["ChatTemplatesResource", "AsyncChatTemplatesResource"] class ChatTemplatesResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> ChatTemplatesResourceWithRawResponse: """ @@ -52,6 +55,7 @@ def create( display_order: int, image_url: str, is_active: bool, + questions: Iterable[TemplateQuestionParam], title: 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. @@ -79,6 +83,7 @@ def create( "display_order": display_order, "image_url": image_url, "is_active": is_active, + "questions": questions, "title": title, }, chat_template_create_params.ChatTemplateCreateParams, @@ -97,6 +102,7 @@ def update( display_order: Optional[int] | Omit = omit, image_url: Optional[str] | Omit = omit, is_active: Optional[bool] | Omit = omit, + questions: Optional[Iterable[TemplateQuestionParam]] | Omit = omit, title: Optional[str] | Omit = omit, updated_by: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -119,13 +125,14 @@ def update( if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") return self._patch( - f"/admin/chat/templates/{template_id}", + path_template("/admin/chat/templates/{template_id}", template_id=template_id), body=maybe_transform( { "description": description, "display_order": display_order, "image_url": image_url, "is_active": is_active, + "questions": questions, "title": title, "updated_by": updated_by, }, @@ -174,6 +181,8 @@ def list( class AsyncChatTemplatesResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncChatTemplatesResourceWithRawResponse: """ @@ -201,6 +210,7 @@ async def create( display_order: int, image_url: str, is_active: bool, + questions: Iterable[TemplateQuestionParam], title: 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. @@ -228,6 +238,7 @@ async def create( "display_order": display_order, "image_url": image_url, "is_active": is_active, + "questions": questions, "title": title, }, chat_template_create_params.ChatTemplateCreateParams, @@ -246,6 +257,7 @@ async def update( display_order: Optional[int] | Omit = omit, image_url: Optional[str] | Omit = omit, is_active: Optional[bool] | Omit = omit, + questions: Optional[Iterable[TemplateQuestionParam]] | Omit = omit, title: Optional[str] | Omit = omit, updated_by: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -268,13 +280,14 @@ async def update( if not template_id: raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") return await self._patch( - f"/admin/chat/templates/{template_id}", + path_template("/admin/chat/templates/{template_id}", template_id=template_id), body=await async_maybe_transform( { "description": description, "display_order": display_order, "image_url": image_url, "is_active": is_active, + "questions": questions, "title": title, "updated_by": updated_by, }, diff --git a/src/structify/resources/admin/connector.py b/src/structify/resources/admin/connector.py index 85e094b90..0c05e7d0b 100644 --- a/src/structify/resources/admin/connector.py +++ b/src/structify/resources/admin/connector.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional import httpx -from ..._types import Body, Query, Headers, NotGiven, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -16,15 +16,21 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...types.admin import connector_clone_params +from ...types.admin import DatahubIngestionType, connector_clone_params, connector_set_datahub_config_params from ..._base_client import make_request_options -from ...types.admin.clone_connectors_response import CloneConnectorsResponse +from ...types.connector import Connector +from ...types.datahub_secret_map_param import DatahubSecretMapParam +from ...types.admin.datahub_ingestion_type import DatahubIngestionType +from ...types.admin.connector_clone_response import ConnectorCloneResponse from ...types.admin.clone_connector_item_param import CloneConnectorItemParam +from ...types.admin.admin_list_connectors_response import AdminListConnectorsResponse __all__ = ["ConnectorResource", "AsyncConnectorResource"] class ConnectorResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> ConnectorResourceWithRawResponse: """ @@ -48,6 +54,8 @@ def clone( self, *, connectors: Iterable[CloneConnectorItemParam], + source_membership_id: str, + source_team_id: str, target_team_id: 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. @@ -55,7 +63,7 @@ def clone( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CloneConnectorsResponse: + ) -> ConnectorCloneResponse: """ Args: extra_headers: Send extra headers @@ -71,6 +79,8 @@ def clone( body=maybe_transform( { "connectors": connectors, + "source_membership_id": source_membership_id, + "source_team_id": source_team_id, "target_team_id": target_team_id, }, connector_clone_params.ConnectorCloneParams, @@ -78,11 +88,86 @@ def clone( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=CloneConnectorsResponse, + cast_to=ConnectorCloneResponse, + ) + + def list_team_connectors( + self, + team_id: 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, + ) -> AdminListConnectorsResponse: + """ + 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 + """ + if not team_id: + raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") + return self._get( + path_template("/admin/connector/team/{team_id}", team_id=team_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AdminListConnectorsResponse, + ) + + def set_datahub_config( + self, + *, + connector_id: str, + datahub_ingestion_type: Optional[DatahubIngestionType] | Omit = omit, + datahub_secret_map: Optional[DatahubSecretMapParam] | Omit = omit, + # 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, + ) -> Connector: + """ + Args: + datahub_secret_map: Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + + 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._post( + "/admin/connector/datahub-config", + body=maybe_transform( + { + "connector_id": connector_id, + "datahub_ingestion_type": datahub_ingestion_type, + "datahub_secret_map": datahub_secret_map, + }, + connector_set_datahub_config_params.ConnectorSetDatahubConfigParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Connector, ) class AsyncConnectorResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncConnectorResourceWithRawResponse: """ @@ -106,6 +191,8 @@ async def clone( self, *, connectors: Iterable[CloneConnectorItemParam], + source_membership_id: str, + source_team_id: str, target_team_id: 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. @@ -113,7 +200,7 @@ async def clone( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CloneConnectorsResponse: + ) -> ConnectorCloneResponse: """ Args: extra_headers: Send extra headers @@ -129,6 +216,8 @@ async def clone( body=await async_maybe_transform( { "connectors": connectors, + "source_membership_id": source_membership_id, + "source_team_id": source_team_id, "target_team_id": target_team_id, }, connector_clone_params.ConnectorCloneParams, @@ -136,7 +225,80 @@ async def clone( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=CloneConnectorsResponse, + cast_to=ConnectorCloneResponse, + ) + + async def list_team_connectors( + self, + team_id: 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, + ) -> AdminListConnectorsResponse: + """ + 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 + """ + if not team_id: + raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") + return await self._get( + path_template("/admin/connector/team/{team_id}", team_id=team_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AdminListConnectorsResponse, + ) + + async def set_datahub_config( + self, + *, + connector_id: str, + datahub_ingestion_type: Optional[DatahubIngestionType] | Omit = omit, + datahub_secret_map: Optional[DatahubSecretMapParam] | Omit = omit, + # 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, + ) -> Connector: + """ + Args: + datahub_secret_map: Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + + 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._post( + "/admin/connector/datahub-config", + body=await async_maybe_transform( + { + "connector_id": connector_id, + "datahub_ingestion_type": datahub_ingestion_type, + "datahub_secret_map": datahub_secret_map, + }, + connector_set_datahub_config_params.ConnectorSetDatahubConfigParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Connector, ) @@ -147,6 +309,12 @@ def __init__(self, connector: ConnectorResource) -> None: self.clone = to_raw_response_wrapper( connector.clone, ) + self.list_team_connectors = to_raw_response_wrapper( + connector.list_team_connectors, + ) + self.set_datahub_config = to_raw_response_wrapper( + connector.set_datahub_config, + ) class AsyncConnectorResourceWithRawResponse: @@ -156,6 +324,12 @@ def __init__(self, connector: AsyncConnectorResource) -> None: self.clone = async_to_raw_response_wrapper( connector.clone, ) + self.list_team_connectors = async_to_raw_response_wrapper( + connector.list_team_connectors, + ) + self.set_datahub_config = async_to_raw_response_wrapper( + connector.set_datahub_config, + ) class ConnectorResourceWithStreamingResponse: @@ -165,6 +339,12 @@ def __init__(self, connector: ConnectorResource) -> None: self.clone = to_streamed_response_wrapper( connector.clone, ) + self.list_team_connectors = to_streamed_response_wrapper( + connector.list_team_connectors, + ) + self.set_datahub_config = to_streamed_response_wrapper( + connector.set_datahub_config, + ) class AsyncConnectorResourceWithStreamingResponse: @@ -174,3 +354,9 @@ def __init__(self, connector: AsyncConnectorResource) -> None: self.clone = async_to_streamed_response_wrapper( connector.clone, ) + self.list_team_connectors = async_to_streamed_response_wrapper( + connector.list_team_connectors, + ) + self.set_datahub_config = async_to_streamed_response_wrapper( + connector.set_datahub_config, + ) diff --git a/src/structify/resources/admin/dataset.py b/src/structify/resources/admin/dataset.py index cf49a6553..aee899163 100644 --- a/src/structify/resources/admin/dataset.py +++ b/src/structify/resources/admin/dataset.py @@ -22,6 +22,8 @@ class DatasetResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> DatasetResourceWithRawResponse: """ @@ -78,6 +80,8 @@ def get_by_id( class AsyncDatasetResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncDatasetResourceWithRawResponse: """ diff --git a/src/structify/resources/admin/functional_tests.py b/src/structify/resources/admin/functional_tests.py index 2cec2b8d0..2497a10df 100644 --- a/src/structify/resources/admin/functional_tests.py +++ b/src/structify/resources/admin/functional_tests.py @@ -31,6 +31,8 @@ class FunctionalTestsResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> FunctionalTestsResourceWithRawResponse: """ @@ -268,6 +270,8 @@ def update_results( class AsyncFunctionalTestsResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncFunctionalTestsResourceWithRawResponse: """ diff --git a/src/structify/resources/admin/jobs.py b/src/structify/resources/admin/jobs.py index 63173942d..424b118db 100644 --- a/src/structify/resources/admin/jobs.py +++ b/src/structify/resources/admin/jobs.py @@ -2,8 +2,7 @@ from __future__ import annotations -from typing import Union, Optional -from datetime import datetime +from typing import Optional from typing_extensions import Literal import httpx @@ -19,15 +18,21 @@ async_to_streamed_response_wrapper, ) from ...pagination import SyncJobsList, AsyncJobsList -from ...types.admin import job_list_params, job_delete_params +from ...types.admin import job_list_params, job_delete_params, job_kill_by_user_params, job_update_concurrency_params from ..._base_client import AsyncPaginator, make_request_options -from ...types.admin.admin_list_jobs_response import AdminListJobsResponse +from ...types.admin.job_list_response import JobListResponse +from ...types.admin.job_concurrency_response import JobConcurrencyResponse +from ...types.admin.job_kill_by_user_response import JobKillByUserResponse from ...types.admin.admin_delete_jobs_response import AdminDeleteJobsResponse +from ...types.admin.job_running_stats_response import JobRunningStatsResponse +from ...types.admin.job_update_concurrency_response import JobUpdateConcurrencyResponse __all__ = ["JobsResource", "AsyncJobsResource"] class JobsResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> JobsResourceWithRawResponse: """ @@ -50,41 +55,21 @@ def with_streaming_response(self) -> JobsResourceWithStreamingResponse: def list( self, *, - filter_test_users: bool, - limit: int, - offset: int, - dataset_id: Optional[str] | Omit = omit, - seeded_kg_search_term: Optional[str] | Omit = omit, - since: Union[str, datetime, None] | Omit = omit, + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] + | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, status: Optional[Literal["Queued", "Running", "Completed", "Failed"]] | Omit = omit, + user_id: Optional[str] | Omit = omit, # 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, - ) -> SyncJobsList[AdminListJobsResponse]: + ) -> SyncJobsList[JobListResponse]: """ - This endpoint allows admins to list jobs from all users without user ownership - restrictions. Optionally filter out test users (users with functional_test - feature flag or debug permission). - Args: - filter_test_users: Filter out jobs from test users (users with functional_test feature flag or - debug permission) - - limit: Number of results to return - - offset: Pagination offset - - dataset_id: Dataset ID to optionally filter jobs by - - seeded_kg_search_term: Seeded kg search term - - since: List since a specific timestamp - - status: Status to optionally filter jobs by - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -95,7 +80,7 @@ def list( """ return self._get_api_list( "/admin/jobs/list", - page=SyncJobsList[AdminListJobsResponse], + page=SyncJobsList[JobListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -103,18 +88,16 @@ def list( timeout=timeout, query=maybe_transform( { - "filter_test_users": filter_test_users, + "job_type": job_type, "limit": limit, "offset": offset, - "dataset_id": dataset_id, - "seeded_kg_search_term": seeded_kg_search_term, - "since": since, "status": status, + "user_id": user_id, }, job_list_params.JobListParams, ), ), - model=AdminListJobsResponse, + model=JobListResponse, ) def delete( @@ -147,8 +130,123 @@ def delete( cast_to=AdminDeleteJobsResponse, ) + def concurrency( + 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, + ) -> JobConcurrencyResponse: + return self._get( + "/admin/jobs/concurrency_limits", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobConcurrencyResponse, + ) + + def kill_by_user( + self, + *, + user_id: 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, + ) -> JobKillByUserResponse: + """ + 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._post( + "/admin/jobs/kill_by_user", + body=maybe_transform({"user_id": user_id}, job_kill_by_user_params.JobKillByUserParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobKillByUserResponse, + ) + + def running_stats( + 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, + ) -> JobRunningStatsResponse: + return self._get( + "/admin/jobs/running_stats", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobRunningStatsResponse, + ) + + def update_concurrency( + self, + *, + max_connector_explore_jobs: Optional[int] | Omit = omit, + max_derive_jobs: Optional[int] | Omit = omit, + max_match_jobs: Optional[int] | Omit = omit, + max_pdf_jobs: Optional[int] | Omit = omit, + max_scrape_jobs: Optional[int] | Omit = omit, + max_total_jobs: Optional[int] | Omit = omit, + max_web_jobs: Optional[int] | Omit = omit, + # 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, + ) -> JobUpdateConcurrencyResponse: + """ + 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._put( + "/admin/jobs/concurrency_limits", + body=maybe_transform( + { + "max_connector_explore_jobs": max_connector_explore_jobs, + "max_derive_jobs": max_derive_jobs, + "max_match_jobs": max_match_jobs, + "max_pdf_jobs": max_pdf_jobs, + "max_scrape_jobs": max_scrape_jobs, + "max_total_jobs": max_total_jobs, + "max_web_jobs": max_web_jobs, + }, + job_update_concurrency_params.JobUpdateConcurrencyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobUpdateConcurrencyResponse, + ) + class AsyncJobsResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncJobsResourceWithRawResponse: """ @@ -171,41 +269,21 @@ def with_streaming_response(self) -> AsyncJobsResourceWithStreamingResponse: def list( self, *, - filter_test_users: bool, - limit: int, - offset: int, - dataset_id: Optional[str] | Omit = omit, - seeded_kg_search_term: Optional[str] | Omit = omit, - since: Union[str, datetime, None] | Omit = omit, + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] + | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, status: Optional[Literal["Queued", "Running", "Completed", "Failed"]] | Omit = omit, + user_id: Optional[str] | Omit = omit, # 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, - ) -> AsyncPaginator[AdminListJobsResponse, AsyncJobsList[AdminListJobsResponse]]: + ) -> AsyncPaginator[JobListResponse, AsyncJobsList[JobListResponse]]: """ - This endpoint allows admins to list jobs from all users without user ownership - restrictions. Optionally filter out test users (users with functional_test - feature flag or debug permission). - Args: - filter_test_users: Filter out jobs from test users (users with functional_test feature flag or - debug permission) - - limit: Number of results to return - - offset: Pagination offset - - dataset_id: Dataset ID to optionally filter jobs by - - seeded_kg_search_term: Seeded kg search term - - since: List since a specific timestamp - - status: Status to optionally filter jobs by - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -216,7 +294,7 @@ def list( """ return self._get_api_list( "/admin/jobs/list", - page=AsyncJobsList[AdminListJobsResponse], + page=AsyncJobsList[JobListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -224,18 +302,16 @@ def list( timeout=timeout, query=maybe_transform( { - "filter_test_users": filter_test_users, + "job_type": job_type, "limit": limit, "offset": offset, - "dataset_id": dataset_id, - "seeded_kg_search_term": seeded_kg_search_term, - "since": since, "status": status, + "user_id": user_id, }, job_list_params.JobListParams, ), ), - model=AdminListJobsResponse, + model=JobListResponse, ) async def delete( @@ -268,6 +344,119 @@ async def delete( cast_to=AdminDeleteJobsResponse, ) + async def concurrency( + 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, + ) -> JobConcurrencyResponse: + return await self._get( + "/admin/jobs/concurrency_limits", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobConcurrencyResponse, + ) + + async def kill_by_user( + self, + *, + user_id: 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, + ) -> JobKillByUserResponse: + """ + 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._post( + "/admin/jobs/kill_by_user", + body=await async_maybe_transform({"user_id": user_id}, job_kill_by_user_params.JobKillByUserParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobKillByUserResponse, + ) + + async def running_stats( + 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, + ) -> JobRunningStatsResponse: + return await self._get( + "/admin/jobs/running_stats", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobRunningStatsResponse, + ) + + async def update_concurrency( + self, + *, + max_connector_explore_jobs: Optional[int] | Omit = omit, + max_derive_jobs: Optional[int] | Omit = omit, + max_match_jobs: Optional[int] | Omit = omit, + max_pdf_jobs: Optional[int] | Omit = omit, + max_scrape_jobs: Optional[int] | Omit = omit, + max_total_jobs: Optional[int] | Omit = omit, + max_web_jobs: Optional[int] | Omit = omit, + # 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, + ) -> JobUpdateConcurrencyResponse: + """ + 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._put( + "/admin/jobs/concurrency_limits", + body=await async_maybe_transform( + { + "max_connector_explore_jobs": max_connector_explore_jobs, + "max_derive_jobs": max_derive_jobs, + "max_match_jobs": max_match_jobs, + "max_pdf_jobs": max_pdf_jobs, + "max_scrape_jobs": max_scrape_jobs, + "max_total_jobs": max_total_jobs, + "max_web_jobs": max_web_jobs, + }, + job_update_concurrency_params.JobUpdateConcurrencyParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=JobUpdateConcurrencyResponse, + ) + class JobsResourceWithRawResponse: def __init__(self, jobs: JobsResource) -> None: @@ -279,6 +468,18 @@ def __init__(self, jobs: JobsResource) -> None: self.delete = to_raw_response_wrapper( jobs.delete, ) + self.concurrency = to_raw_response_wrapper( + jobs.concurrency, + ) + self.kill_by_user = to_raw_response_wrapper( + jobs.kill_by_user, + ) + self.running_stats = to_raw_response_wrapper( + jobs.running_stats, + ) + self.update_concurrency = to_raw_response_wrapper( + jobs.update_concurrency, + ) class AsyncJobsResourceWithRawResponse: @@ -291,6 +492,18 @@ def __init__(self, jobs: AsyncJobsResource) -> None: self.delete = async_to_raw_response_wrapper( jobs.delete, ) + self.concurrency = async_to_raw_response_wrapper( + jobs.concurrency, + ) + self.kill_by_user = async_to_raw_response_wrapper( + jobs.kill_by_user, + ) + self.running_stats = async_to_raw_response_wrapper( + jobs.running_stats, + ) + self.update_concurrency = async_to_raw_response_wrapper( + jobs.update_concurrency, + ) class JobsResourceWithStreamingResponse: @@ -303,6 +516,18 @@ def __init__(self, jobs: JobsResource) -> None: self.delete = to_streamed_response_wrapper( jobs.delete, ) + self.concurrency = to_streamed_response_wrapper( + jobs.concurrency, + ) + self.kill_by_user = to_streamed_response_wrapper( + jobs.kill_by_user, + ) + self.running_stats = to_streamed_response_wrapper( + jobs.running_stats, + ) + self.update_concurrency = to_streamed_response_wrapper( + jobs.update_concurrency, + ) class AsyncJobsResourceWithStreamingResponse: @@ -315,3 +540,15 @@ def __init__(self, jobs: AsyncJobsResource) -> None: self.delete = async_to_streamed_response_wrapper( jobs.delete, ) + self.concurrency = async_to_streamed_response_wrapper( + jobs.concurrency, + ) + self.kill_by_user = async_to_streamed_response_wrapper( + jobs.kill_by_user, + ) + self.running_stats = async_to_streamed_response_wrapper( + jobs.running_stats, + ) + self.update_concurrency = async_to_streamed_response_wrapper( + jobs.update_concurrency, + ) diff --git a/src/structify/resources/admin/sandbox.py b/src/structify/resources/admin/sandbox.py index 413ec58f5..141c56569 100644 --- a/src/structify/resources/admin/sandbox.py +++ b/src/structify/resources/admin/sandbox.py @@ -25,6 +25,8 @@ class SandboxResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> SandboxResourceWithRawResponse: """ @@ -87,6 +89,8 @@ def list( class AsyncSandboxResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncSandboxResourceWithRawResponse: """ diff --git a/src/structify/resources/admin/teams.py b/src/structify/resources/admin/teams.py index dc9e4e015..5d6c1799c 100644 --- a/src/structify/resources/admin/teams.py +++ b/src/structify/resources/admin/teams.py @@ -10,7 +10,7 @@ from ...types import TeamRole from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -19,7 +19,6 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...pagination import SyncJobsList, AsyncJobsList from ...types.admin import ( team_list_params, team_add_member_params, @@ -31,13 +30,13 @@ team_create_subscription_params, team_update_seats_override_params, ) -from ..._base_client import AsyncPaginator, make_request_options +from ..._base_client import make_request_options from ...types.team_role import TeamRole +from ...types.admin.team_list_response import TeamListResponse from ...types.admin.extend_trial_response import ExtendTrialResponse from ...types.admin.expire_grants_response import ExpireGrantsResponse from ...types.admin.grant_credits_response import GrantCreditsResponse from ...types.admin.admin_add_member_response import AdminAddMemberResponse -from ...types.admin.admin_teams_list_response import AdminTeamsListResponse from ...types.admin.admin_list_members_response import AdminListMembersResponse from ...types.admin.admin_remove_member_response import AdminRemoveMemberResponse from ...types.admin.cancel_subscription_response import CancelSubscriptionResponse @@ -48,6 +47,8 @@ class TeamsResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> TeamsResourceWithRawResponse: """ @@ -72,17 +73,18 @@ def list( *, limit: Optional[int] | Omit = omit, offset: Optional[int] | Omit = omit, + search: Optional[str] | Omit = omit, # 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, - ) -> SyncJobsList[AdminTeamsListResponse]: + ) -> TeamListResponse: """ Lists teams in the system along with their subscription information, credit - grants, and member counts. Supports optional pagination via limit and offset - query parameters. + grants, and member counts. Supports optional pagination via limit, offset, and + search query parameters. Args: extra_headers: Send extra headers @@ -93,9 +95,8 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get_api_list( + return self._get( "/admin/team/list", - page=SyncJobsList[AdminTeamsListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -105,11 +106,12 @@ def list( { "limit": limit, "offset": offset, + "search": search, }, team_list_params.TeamListParams, ), ), - model=AdminTeamsListResponse, + cast_to=TeamListResponse, ) def add_member( @@ -373,7 +375,7 @@ def list_members( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/admin/team/{team_id}/members", + path_template("/admin/team/{team_id}/members", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -456,6 +458,8 @@ def update_seats_override( class AsyncTeamsResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncTeamsResourceWithRawResponse: """ @@ -475,22 +479,23 @@ def with_streaming_response(self) -> AsyncTeamsResourceWithStreamingResponse: """ return AsyncTeamsResourceWithStreamingResponse(self) - def list( + async def list( self, *, limit: Optional[int] | Omit = omit, offset: Optional[int] | Omit = omit, + search: Optional[str] | Omit = omit, # 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, - ) -> AsyncPaginator[AdminTeamsListResponse, AsyncJobsList[AdminTeamsListResponse]]: + ) -> TeamListResponse: """ Lists teams in the system along with their subscription information, credit - grants, and member counts. Supports optional pagination via limit and offset - query parameters. + grants, and member counts. Supports optional pagination via limit, offset, and + search query parameters. Args: extra_headers: Send extra headers @@ -501,23 +506,23 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get_api_list( + return await self._get( "/admin/team/list", - page=AsyncJobsList[AdminTeamsListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform( + query=await async_maybe_transform( { "limit": limit, "offset": offset, + "search": search, }, team_list_params.TeamListParams, ), ), - model=AdminTeamsListResponse, + cast_to=TeamListResponse, ) async def add_member( @@ -783,7 +788,7 @@ async def list_members( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/admin/team/{team_id}/members", + path_template("/admin/team/{team_id}/members", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/admin/users.py b/src/structify/resources/admin/users.py index 7b17e7ff6..8ff3d38cb 100644 --- a/src/structify/resources/admin/users.py +++ b/src/structify/resources/admin/users.py @@ -29,6 +29,8 @@ class UsersResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> UsersResourceWithRawResponse: """ @@ -206,6 +208,8 @@ def impersonate( class AsyncUsersResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: """ diff --git a/src/structify/resources/chat.py b/src/structify/resources/chat.py index 0c8d58d2f..1d29f7dbb 100644 --- a/src/structify/resources/chat.py +++ b/src/structify/resources/chat.py @@ -2,7 +2,9 @@ from __future__ import annotations -from typing import Optional +from typing import Union, Mapping, Optional, cast +from datetime import datetime +from typing_extensions import Literal import httpx @@ -11,39 +13,54 @@ ChatSessionRole, chat_copy_params, chat_load_files_params, - chat_delete_files_params, chat_list_sessions_params, chat_add_git_commit_params, chat_create_session_params, chat_update_session_params, + chat_list_dashboards_params, + chat_simulate_prompt_params, chat_add_collaborator_params, + chat_load_input_files_params, chat_revert_to_commit_params, chat_admin_issue_found_params, + chat_delete_input_file_params, chat_update_visibility_params, + chat_upload_input_file_params, chat_grant_admin_override_params, chat_update_session_favorite_params, chat_copy_node_output_by_code_hash_params, ) -from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, SequenceNotStr, omit, not_given +from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, to_raw_response_wrapper, to_streamed_response_wrapper, async_to_raw_response_wrapper, + to_custom_raw_response_wrapper, async_to_streamed_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_raw_response_wrapper, + async_to_custom_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.chat_prompt import ChatPrompt from ..types.chat_session import ChatSession +from ..types.chat_template import ChatTemplate from ..types.chat_visibility import ChatVisibility +from ..types.chat_prompt_param import ChatPromptParam from ..types.chat_session_role import ChatSessionRole +from ..types.compress_chat_response import CompressChatResponse from ..types.chat_load_files_response import ChatLoadFilesResponse +from ..types.list_dashboards_response import ListDashboardsResponse +from ..types.simulate_prompt_response import SimulatePromptResponse from ..types.get_chat_session_response import GetChatSessionResponse from ..types.get_dependencies_response import GetDependenciesResponse from ..types.admin_issue_found_response import AdminIssueFoundResponse -from ..types.chat_delete_files_response import ChatDeleteFilesResponse from ..types.chat_session_with_messages import ChatSessionWithMessages from ..types.update_visibility_response import UpdateVisibilityResponse from ..types.admin_grant_access_response import AdminGrantAccessResponse @@ -54,9 +71,14 @@ from ..types.chat_list_templates_response import ChatListTemplatesResponse from ..types.create_chat_session_response import CreateChatSessionResponse from ..types.delete_chat_session_response import DeleteChatSessionResponse +from ..types.chat_list_input_files_response import ChatListInputFilesResponse +from ..types.chat_load_input_files_response import ChatLoadInputFilesResponse from ..types.chat_revert_to_commit_response import ChatRevertToCommitResponse +from ..types.chat_delete_input_file_response import ChatDeleteInputFileResponse from ..types.chat_get_partial_chats_response import ChatGetPartialChatsResponse +from ..types.chat_upload_input_file_response import ChatUploadInputFileResponse from ..types.chat_get_session_timeline_response import ChatGetSessionTimelineResponse +from ..types.chat_copy_node_output_by_code_hash_response import ChatCopyNodeOutputByCodeHashResponse __all__ = ["ChatResource", "AsyncChatResource"] @@ -108,7 +130,7 @@ def add_collaborator( raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/chat/sessions/{chat_id}/collaborators", + path_template("/chat/sessions/{chat_id}/collaborators", chat_id=chat_id), body=maybe_transform( { "email": email, @@ -151,7 +173,7 @@ def add_git_commit( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/chat/sessions/{session_id}/commits", + path_template("/chat/sessions/{session_id}/commits", session_id=session_id), body=maybe_transform({"commit_hash": commit_hash}, chat_add_git_commit_params.ChatAddGitCommitParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -159,20 +181,21 @@ def add_git_commit( cast_to=ChatAddGitCommitResponse, ) - def admin_get_chat_prompt( + def admin_issue_found( self, - session_id: str, + chat_id: str, *, + message: str, + title: 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, - ) -> ChatPrompt: + ) -> AdminIssueFoundResponse: """ - Get the actual chat prompt that the LLM will see on its next message (admin - only) + Add an IssueFound tool call as an admin-only auto-review message Args: extra_headers: Send extra headers @@ -183,32 +206,35 @@ def admin_get_chat_prompt( timeout: Override the client-level default timeout for this request, in seconds """ - if not session_id: - raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") - return self._get( - f"/chat/sessions/{session_id}/admin/chat_prompt", + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return self._post( + path_template("/chat/sessions/{chat_id}/admin/issue_found", chat_id=chat_id), + body=maybe_transform( + { + "message": message, + "title": title, + }, + chat_admin_issue_found_params.ChatAdminIssueFoundParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ChatPrompt, + cast_to=AdminIssueFoundResponse, ) - def admin_issue_found( + def compress( self, - chat_id: str, + session_id: str, *, - message: str, - title: 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, - ) -> AdminIssueFoundResponse: + ) -> CompressChatResponse: """ - Add an IssueFound tool call as an admin-only auto-review message - Args: extra_headers: Send extra headers @@ -218,21 +244,14 @@ def admin_issue_found( timeout: Override the client-level default timeout for this request, in seconds """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/chat/sessions/{chat_id}/admin/issue_found", - body=maybe_transform( - { - "message": message, - "title": title, - }, - chat_admin_issue_found_params.ChatAdminIssueFoundParams, - ), + path_template("/chat/sessions/{session_id}/compress", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AdminIssueFoundResponse, + cast_to=CompressChatResponse, ) def copy( @@ -243,6 +262,7 @@ def copy( team_id: str, copy_inputs: bool | Omit = omit, project_id: Optional[str] | Omit = omit, + template_id: Optional[str] | Omit = omit, # 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, @@ -271,6 +291,7 @@ def copy( "team_id": team_id, "copy_inputs": copy_inputs, "project_id": project_id, + "template_id": template_id, }, chat_copy_params.ChatCopyParams, ), @@ -292,7 +313,7 @@ def copy_node_output_by_code_hash( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: + ) -> ChatCopyNodeOutputByCodeHashResponse: """ Args: extra_headers: Send extra headers @@ -306,7 +327,7 @@ def copy_node_output_by_code_hash( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/chat/sessions/{session_id}/nodes/by_code_hash", + path_template("/chat/sessions/{session_id}/nodes/by_code_hash", session_id=session_id), body=maybe_transform( { "code_md5_hash": code_md5_hash, @@ -317,7 +338,7 @@ def copy_node_output_by_code_hash( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=str, + cast_to=ChatCopyNodeOutputByCodeHashResponse, ) def create_session( @@ -326,7 +347,6 @@ def create_session( team_id: str, config: Optional[chat_create_session_params.Config] | Omit = omit, ephemeral: Optional[bool] | Omit = omit, - initial_message: Optional[str] | Omit = omit, project_id: Optional[str] | Omit = omit, # 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. @@ -356,7 +376,6 @@ def create_session( "team_id": team_id, "config": config, "ephemeral": ephemeral, - "initial_message": initial_message, "project_id": project_id, }, chat_create_session_params.ChatCreateSessionParams, @@ -367,20 +386,20 @@ def create_session( cast_to=CreateChatSessionResponse, ) - def delete_files( + def delete_input_file( self, chat_id: str, *, - paths: SequenceNotStr[str], + filenames: SequenceNotStr[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, - ) -> ChatDeleteFilesResponse: + ) -> ChatDeleteInputFileResponse: """ - Delete files from a chat session's git repository + Delete input files from a chat session Args: extra_headers: Send extra headers @@ -394,12 +413,12 @@ def delete_files( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return self._post( - f"/chat/files/delete/{chat_id}", - body=maybe_transform({"paths": paths}, chat_delete_files_params.ChatDeleteFilesParams), + path_template("/chat/input-files/delete/{chat_id}", chat_id=chat_id), + body=maybe_transform({"filenames": filenames}, chat_delete_input_file_params.ChatDeleteInputFileParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ChatDeleteFilesResponse, + cast_to=ChatDeleteInputFileResponse, ) def delete_session( @@ -428,7 +447,7 @@ def delete_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._delete( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -461,7 +480,7 @@ def get_dependencies( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._get( - f"/chat/sessions/{session_id}/dependencies", + path_template("/chat/sessions/{session_id}/dependencies", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -497,7 +516,7 @@ def get_git_commit( if not commit_hash: raise ValueError(f"Expected a non-empty value for `commit_hash` but received {commit_hash!r}") return self._get( - f"/chat/sessions/{chat_id}/commits/{commit_hash}", + path_template("/chat/sessions/{chat_id}/commits/{commit_hash}", chat_id=chat_id, commit_hash=commit_hash), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -530,7 +549,7 @@ def get_partial_chats( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return self._get( - f"/chat/{chat_session_id}/partial-chats", + path_template("/chat/{chat_session_id}/partial-chats", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -563,7 +582,7 @@ def get_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._get( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -596,13 +615,44 @@ def get_session_timeline( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._get( - f"/chat/sessions/{session_id}/timeline", + path_template("/chat/sessions/{session_id}/timeline", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ChatGetSessionTimelineResponse, ) + def get_template( + self, + template_id: 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, + ) -> ChatTemplate: + """ + 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 + """ + if not template_id: + raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + return self._get( + path_template("/chat/templates/{template_id}", template_id=template_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatTemplate, + ) + def grant_admin_override( self, chat_id: str, @@ -633,7 +683,7 @@ def grant_admin_override( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return self._post( - f"/chat/sessions/{chat_id}/admin_override", + path_template("/chat/sessions/{chat_id}/admin_override", chat_id=chat_id), body=maybe_transform( { "duration_hours": duration_hours, @@ -673,19 +723,98 @@ def list_collaborators( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return self._get( - f"/chat/sessions/{chat_id}/collaborators", + path_template("/chat/sessions/{chat_id}/collaborators", chat_id=chat_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ListCollaboratorsResponse, ) + def list_dashboards( + self, + chat_id: str, + *, + commit_hash: Optional[str] | Omit = omit, + # 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, + ) -> ListDashboardsResponse: + """ + List dashboard specs for a chat session at a specific commit hash. + + Args: + commit_hash: Optional commit hash. If omitted, uses the chat session latest commit. + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return self._get( + path_template("/chat/sessions/{chat_id}/dashboards", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"commit_hash": commit_hash}, chat_list_dashboards_params.ChatListDashboardsParams + ), + ), + cast_to=ListDashboardsResponse, + ) + + def list_input_files( + self, + chat_id: 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, + ) -> ChatListInputFilesResponse: + """ + List input files for a chat session + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return self._get( + path_template("/chat/input-files/list/{chat_id}", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatListInputFilesResponse, + ) + def list_sessions( self, *, team_id: str, + connector_id: Optional[str] | Omit = omit, limit: Optional[int] | Omit = omit, + offset: Optional[int] | Omit = omit, project_id: Optional[str] | Omit = omit, + search: Optional[str] | Omit = omit, + tab: Optional[Literal["my_chats", "favorites", "shared", "team", "recents", "from_messaging"]] | Omit = omit, # 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, @@ -700,10 +829,18 @@ def list_sessions( Args: team_id: Team ID to filter chat sessions + connector_id: Connector ID to filter chat sessions that use this connector + limit: Maximum number of sessions to return (default: 50) + offset: Number of sessions to skip (default: 0) + project_id: Project ID to filter chat sessions + search: Search query to filter sessions by name (case-insensitive) + + tab: Tab filter for chat sessions + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -722,8 +859,12 @@ def list_sessions( query=maybe_transform( { "team_id": team_id, + "connector_id": connector_id, "limit": limit, + "offset": offset, "project_id": project_id, + "search": search, + "tab": tab, }, chat_list_sessions_params.ChatListSessionsParams, ), @@ -789,6 +930,83 @@ def load_files( cast_to=ChatLoadFilesResponse, ) + def load_input_file( + self, + filename: str, + *, + chat_id: 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, + ) -> BinaryAPIResponse: + """ + Download a single input file by chat ID and filename + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + if not filename: + raise ValueError(f"Expected a non-empty value for `filename` but received {filename!r}") + extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} + return self._get( + path_template("/chat/input-files/download/{chat_id}/{filename}", chat_id=chat_id, filename=filename), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryAPIResponse, + ) + + def load_input_files( + self, + chat_id: str, + *, + since: Union[str, datetime, None] | Omit = omit, + # 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, + ) -> ChatLoadInputFilesResponse: + """ + Pass `since` query param (RFC 3339 timestamp) to only get files created/updated + after that time. The response includes `latest_timestamp` which can be passed as + `since` on the next call. + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return self._get( + path_template("/chat/input-files/download-all/{chat_id}", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"since": since}, chat_load_input_files_params.ChatLoadInputFilesParams), + ), + cast_to=ChatLoadInputFilesResponse, + ) + def make_permanent( self, session_id: str, @@ -816,7 +1034,7 @@ def make_permanent( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._patch( - f"/chat/sessions/{session_id}/make-permanent", + path_template("/chat/sessions/{session_id}/make-permanent", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -851,7 +1069,7 @@ def remove_collaborator( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/chat/sessions/{chat_id}/collaborators/{user_id}", + path_template("/chat/sessions/{chat_id}/collaborators/{user_id}", chat_id=chat_id, user_id=user_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -887,7 +1105,7 @@ def revert_to_commit( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/chat/sessions/{session_id}/revert", + path_template("/chat/sessions/{session_id}/revert", session_id=session_id), body=maybe_transform({"commit_hash": commit_hash}, chat_revert_to_commit_params.ChatRevertToCommitParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -895,10 +1113,46 @@ def revert_to_commit( cast_to=ChatRevertToCommitResponse, ) + def simulate_prompt( + self, + chat_session_id: str, + *, + chat_prompt: ChatPromptParam, + # 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, + ) -> SimulatePromptResponse: + """ + any messages to the database. + + 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 + """ + if not chat_session_id: + raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") + return self._post( + path_template("/chat/{chat_session_id}/simulate-prompt", chat_session_id=chat_session_id), + body=maybe_transform({"chat_prompt": chat_prompt}, chat_simulate_prompt_params.ChatSimulatePromptParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SimulatePromptResponse, + ) + def update_session( self, session_id: str, *, + message_head: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, project_id: Optional[str] | Omit = omit, skip_confirmations: Optional[bool] | Omit = omit, @@ -922,9 +1176,10 @@ def update_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._patch( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), body=maybe_transform( { + "message_head": message_head, "name": name, "project_id": project_id, "skip_confirmations": skip_confirmations, @@ -962,7 +1217,7 @@ def update_session_favorite( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._patch( - f"/chat/sessions/{session_id}/favorite", + path_template("/chat/sessions/{session_id}/favorite", session_id=session_id), body=maybe_transform( {"is_favorite": is_favorite}, chat_update_session_favorite_params.ChatUpdateSessionFavoriteParams ), @@ -999,7 +1254,7 @@ def update_visibility( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._put( - f"/chat/sessions/{session_id}/visibility", + path_template("/chat/sessions/{session_id}/visibility", session_id=session_id), body=maybe_transform({"visibility": visibility}, chat_update_visibility_params.ChatUpdateVisibilityParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1007,6 +1262,56 @@ def update_visibility( cast_to=UpdateVisibilityResponse, ) + def upload_input_file( + self, + chat_id: str, + *, + content: FileTypes, + content_type: str, + file_name: 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, + ) -> ChatUploadInputFileResponse: + """ + Upload an input file to a chat session's bucket storage + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + body = deepcopy_minimal( + { + "content": content, + "content_type": content_type, + "file_name": file_name, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["content"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + path_template("/chat/input-files/upload/{chat_id}", chat_id=chat_id), + body=maybe_transform(body, chat_upload_input_file_params.ChatUploadInputFileParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatUploadInputFileResponse, + ) + class AsyncChatResource(AsyncAPIResource): @cached_property @@ -1055,7 +1360,7 @@ async def add_collaborator( raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/chat/sessions/{chat_id}/collaborators", + path_template("/chat/sessions/{chat_id}/collaborators", chat_id=chat_id), body=await async_maybe_transform( { "email": email, @@ -1098,7 +1403,7 @@ async def add_git_commit( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/chat/sessions/{session_id}/commits", + path_template("/chat/sessions/{session_id}/commits", session_id=session_id), body=await async_maybe_transform( {"commit_hash": commit_hash}, chat_add_git_commit_params.ChatAddGitCommitParams ), @@ -1108,20 +1413,21 @@ async def add_git_commit( cast_to=ChatAddGitCommitResponse, ) - async def admin_get_chat_prompt( + async def admin_issue_found( self, - session_id: str, + chat_id: str, *, + message: str, + title: 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, - ) -> ChatPrompt: + ) -> AdminIssueFoundResponse: """ - Get the actual chat prompt that the LLM will see on its next message (admin - only) + Add an IssueFound tool call as an admin-only auto-review message Args: extra_headers: Send extra headers @@ -1132,32 +1438,35 @@ async def admin_get_chat_prompt( timeout: Override the client-level default timeout for this request, in seconds """ - if not session_id: - raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") - return await self._get( - f"/chat/sessions/{session_id}/admin/chat_prompt", + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return await self._post( + path_template("/chat/sessions/{chat_id}/admin/issue_found", chat_id=chat_id), + body=await async_maybe_transform( + { + "message": message, + "title": title, + }, + chat_admin_issue_found_params.ChatAdminIssueFoundParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ChatPrompt, + cast_to=AdminIssueFoundResponse, ) - async def admin_issue_found( + async def compress( self, - chat_id: str, + session_id: str, *, - message: str, - title: 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, - ) -> AdminIssueFoundResponse: + ) -> CompressChatResponse: """ - Add an IssueFound tool call as an admin-only auto-review message - Args: extra_headers: Send extra headers @@ -1167,21 +1476,14 @@ async def admin_issue_found( timeout: Override the client-level default timeout for this request, in seconds """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/chat/sessions/{chat_id}/admin/issue_found", - body=await async_maybe_transform( - { - "message": message, - "title": title, - }, - chat_admin_issue_found_params.ChatAdminIssueFoundParams, - ), + path_template("/chat/sessions/{session_id}/compress", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AdminIssueFoundResponse, + cast_to=CompressChatResponse, ) async def copy( @@ -1192,6 +1494,7 @@ async def copy( team_id: str, copy_inputs: bool | Omit = omit, project_id: Optional[str] | Omit = omit, + template_id: Optional[str] | Omit = omit, # 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, @@ -1220,6 +1523,7 @@ async def copy( "team_id": team_id, "copy_inputs": copy_inputs, "project_id": project_id, + "template_id": template_id, }, chat_copy_params.ChatCopyParams, ), @@ -1241,7 +1545,7 @@ async def copy_node_output_by_code_hash( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> str: + ) -> ChatCopyNodeOutputByCodeHashResponse: """ Args: extra_headers: Send extra headers @@ -1255,7 +1559,7 @@ async def copy_node_output_by_code_hash( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/chat/sessions/{session_id}/nodes/by_code_hash", + path_template("/chat/sessions/{session_id}/nodes/by_code_hash", session_id=session_id), body=await async_maybe_transform( { "code_md5_hash": code_md5_hash, @@ -1266,7 +1570,7 @@ async def copy_node_output_by_code_hash( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=str, + cast_to=ChatCopyNodeOutputByCodeHashResponse, ) async def create_session( @@ -1275,7 +1579,6 @@ async def create_session( team_id: str, config: Optional[chat_create_session_params.Config] | Omit = omit, ephemeral: Optional[bool] | Omit = omit, - initial_message: Optional[str] | Omit = omit, project_id: Optional[str] | Omit = omit, # 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. @@ -1305,7 +1608,6 @@ async def create_session( "team_id": team_id, "config": config, "ephemeral": ephemeral, - "initial_message": initial_message, "project_id": project_id, }, chat_create_session_params.ChatCreateSessionParams, @@ -1316,20 +1618,20 @@ async def create_session( cast_to=CreateChatSessionResponse, ) - async def delete_files( + async def delete_input_file( self, chat_id: str, *, - paths: SequenceNotStr[str], + filenames: SequenceNotStr[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, - ) -> ChatDeleteFilesResponse: + ) -> ChatDeleteInputFileResponse: """ - Delete files from a chat session's git repository + Delete input files from a chat session Args: extra_headers: Send extra headers @@ -1343,12 +1645,14 @@ async def delete_files( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return await self._post( - f"/chat/files/delete/{chat_id}", - body=await async_maybe_transform({"paths": paths}, chat_delete_files_params.ChatDeleteFilesParams), + path_template("/chat/input-files/delete/{chat_id}", chat_id=chat_id), + body=await async_maybe_transform( + {"filenames": filenames}, chat_delete_input_file_params.ChatDeleteInputFileParams + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ChatDeleteFilesResponse, + cast_to=ChatDeleteInputFileResponse, ) async def delete_session( @@ -1377,7 +1681,7 @@ async def delete_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._delete( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1410,7 +1714,7 @@ async def get_dependencies( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._get( - f"/chat/sessions/{session_id}/dependencies", + path_template("/chat/sessions/{session_id}/dependencies", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1446,7 +1750,7 @@ async def get_git_commit( if not commit_hash: raise ValueError(f"Expected a non-empty value for `commit_hash` but received {commit_hash!r}") return await self._get( - f"/chat/sessions/{chat_id}/commits/{commit_hash}", + path_template("/chat/sessions/{chat_id}/commits/{commit_hash}", chat_id=chat_id, commit_hash=commit_hash), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1479,7 +1783,7 @@ async def get_partial_chats( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return await self._get( - f"/chat/{chat_session_id}/partial-chats", + path_template("/chat/{chat_session_id}/partial-chats", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1512,7 +1816,7 @@ async def get_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._get( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1545,13 +1849,44 @@ async def get_session_timeline( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._get( - f"/chat/sessions/{session_id}/timeline", + path_template("/chat/sessions/{session_id}/timeline", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ChatGetSessionTimelineResponse, ) + async def get_template( + self, + template_id: 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, + ) -> ChatTemplate: + """ + 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 + """ + if not template_id: + raise ValueError(f"Expected a non-empty value for `template_id` but received {template_id!r}") + return await self._get( + path_template("/chat/templates/{template_id}", template_id=template_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatTemplate, + ) + async def grant_admin_override( self, chat_id: str, @@ -1582,7 +1917,7 @@ async def grant_admin_override( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return await self._post( - f"/chat/sessions/{chat_id}/admin_override", + path_template("/chat/sessions/{chat_id}/admin_override", chat_id=chat_id), body=await async_maybe_transform( { "duration_hours": duration_hours, @@ -1622,19 +1957,98 @@ async def list_collaborators( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return await self._get( - f"/chat/sessions/{chat_id}/collaborators", + path_template("/chat/sessions/{chat_id}/collaborators", chat_id=chat_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ListCollaboratorsResponse, ) + async def list_dashboards( + self, + chat_id: str, + *, + commit_hash: Optional[str] | Omit = omit, + # 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, + ) -> ListDashboardsResponse: + """ + List dashboard specs for a chat session at a specific commit hash. + + Args: + commit_hash: Optional commit hash. If omitted, uses the chat session latest commit. + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return await self._get( + path_template("/chat/sessions/{chat_id}/dashboards", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"commit_hash": commit_hash}, chat_list_dashboards_params.ChatListDashboardsParams + ), + ), + cast_to=ListDashboardsResponse, + ) + + async def list_input_files( + self, + chat_id: 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, + ) -> ChatListInputFilesResponse: + """ + List input files for a chat session + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return await self._get( + path_template("/chat/input-files/list/{chat_id}", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatListInputFilesResponse, + ) + async def list_sessions( self, *, team_id: str, + connector_id: Optional[str] | Omit = omit, limit: Optional[int] | Omit = omit, + offset: Optional[int] | Omit = omit, project_id: Optional[str] | Omit = omit, + search: Optional[str] | Omit = omit, + tab: Optional[Literal["my_chats", "favorites", "shared", "team", "recents", "from_messaging"]] | Omit = omit, # 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, @@ -1649,10 +2063,18 @@ async def list_sessions( Args: team_id: Team ID to filter chat sessions + connector_id: Connector ID to filter chat sessions that use this connector + limit: Maximum number of sessions to return (default: 50) + offset: Number of sessions to skip (default: 0) + project_id: Project ID to filter chat sessions + search: Search query to filter sessions by name (case-insensitive) + + tab: Tab filter for chat sessions + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1671,8 +2093,12 @@ async def list_sessions( query=await async_maybe_transform( { "team_id": team_id, + "connector_id": connector_id, "limit": limit, + "offset": offset, "project_id": project_id, + "search": search, + "tab": tab, }, chat_list_sessions_params.ChatListSessionsParams, ), @@ -1738,6 +2164,85 @@ async def load_files( cast_to=ChatLoadFilesResponse, ) + async def load_input_file( + self, + filename: str, + *, + chat_id: 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, + ) -> AsyncBinaryAPIResponse: + """ + Download a single input file by chat ID and filename + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + if not filename: + raise ValueError(f"Expected a non-empty value for `filename` but received {filename!r}") + extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} + return await self._get( + path_template("/chat/input-files/download/{chat_id}/{filename}", chat_id=chat_id, filename=filename), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AsyncBinaryAPIResponse, + ) + + async def load_input_files( + self, + chat_id: str, + *, + since: Union[str, datetime, None] | Omit = omit, + # 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, + ) -> ChatLoadInputFilesResponse: + """ + Pass `since` query param (RFC 3339 timestamp) to only get files created/updated + after that time. The response includes `latest_timestamp` which can be passed as + `since` on the next call. + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return await self._get( + path_template("/chat/input-files/download-all/{chat_id}", chat_id=chat_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"since": since}, chat_load_input_files_params.ChatLoadInputFilesParams + ), + ), + cast_to=ChatLoadInputFilesResponse, + ) + async def make_permanent( self, session_id: str, @@ -1765,7 +2270,7 @@ async def make_permanent( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._patch( - f"/chat/sessions/{session_id}/make-permanent", + path_template("/chat/sessions/{session_id}/make-permanent", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1800,7 +2305,7 @@ async def remove_collaborator( raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/chat/sessions/{chat_id}/collaborators/{user_id}", + path_template("/chat/sessions/{chat_id}/collaborators/{user_id}", chat_id=chat_id, user_id=user_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1836,7 +2341,7 @@ async def revert_to_commit( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/chat/sessions/{session_id}/revert", + path_template("/chat/sessions/{session_id}/revert", session_id=session_id), body=await async_maybe_transform( {"commit_hash": commit_hash}, chat_revert_to_commit_params.ChatRevertToCommitParams ), @@ -1846,10 +2351,48 @@ async def revert_to_commit( cast_to=ChatRevertToCommitResponse, ) + async def simulate_prompt( + self, + chat_session_id: str, + *, + chat_prompt: ChatPromptParam, + # 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, + ) -> SimulatePromptResponse: + """ + any messages to the database. + + 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 + """ + if not chat_session_id: + raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") + return await self._post( + path_template("/chat/{chat_session_id}/simulate-prompt", chat_session_id=chat_session_id), + body=await async_maybe_transform( + {"chat_prompt": chat_prompt}, chat_simulate_prompt_params.ChatSimulatePromptParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SimulatePromptResponse, + ) + async def update_session( self, session_id: str, *, + message_head: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, project_id: Optional[str] | Omit = omit, skip_confirmations: Optional[bool] | Omit = omit, @@ -1873,9 +2416,10 @@ async def update_session( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._patch( - f"/chat/sessions/{session_id}", + path_template("/chat/sessions/{session_id}", session_id=session_id), body=await async_maybe_transform( { + "message_head": message_head, "name": name, "project_id": project_id, "skip_confirmations": skip_confirmations, @@ -1913,7 +2457,7 @@ async def update_session_favorite( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._patch( - f"/chat/sessions/{session_id}/favorite", + path_template("/chat/sessions/{session_id}/favorite", session_id=session_id), body=await async_maybe_transform( {"is_favorite": is_favorite}, chat_update_session_favorite_params.ChatUpdateSessionFavoriteParams ), @@ -1950,7 +2494,7 @@ async def update_visibility( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._put( - f"/chat/sessions/{session_id}/visibility", + path_template("/chat/sessions/{session_id}/visibility", session_id=session_id), body=await async_maybe_transform( {"visibility": visibility}, chat_update_visibility_params.ChatUpdateVisibilityParams ), @@ -1960,6 +2504,56 @@ async def update_visibility( cast_to=UpdateVisibilityResponse, ) + async def upload_input_file( + self, + chat_id: str, + *, + content: FileTypes, + content_type: str, + file_name: 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, + ) -> ChatUploadInputFileResponse: + """ + Upload an input file to a chat session's bucket storage + + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + body = deepcopy_minimal( + { + "content": content, + "content_type": content_type, + "file_name": file_name, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["content"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + path_template("/chat/input-files/upload/{chat_id}", chat_id=chat_id), + body=await async_maybe_transform(body, chat_upload_input_file_params.ChatUploadInputFileParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatUploadInputFileResponse, + ) + class ChatResourceWithRawResponse: def __init__(self, chat: ChatResource) -> None: @@ -1971,12 +2565,12 @@ def __init__(self, chat: ChatResource) -> None: self.add_git_commit = to_raw_response_wrapper( chat.add_git_commit, ) - self.admin_get_chat_prompt = to_raw_response_wrapper( - chat.admin_get_chat_prompt, - ) self.admin_issue_found = to_raw_response_wrapper( chat.admin_issue_found, ) + self.compress = to_raw_response_wrapper( + chat.compress, + ) self.copy = to_raw_response_wrapper( chat.copy, ) @@ -1986,8 +2580,8 @@ def __init__(self, chat: ChatResource) -> None: self.create_session = to_raw_response_wrapper( chat.create_session, ) - self.delete_files = to_raw_response_wrapper( - chat.delete_files, + self.delete_input_file = to_raw_response_wrapper( + chat.delete_input_file, ) self.delete_session = to_raw_response_wrapper( chat.delete_session, @@ -2007,12 +2601,21 @@ def __init__(self, chat: ChatResource) -> None: self.get_session_timeline = to_raw_response_wrapper( chat.get_session_timeline, ) + self.get_template = to_raw_response_wrapper( + chat.get_template, + ) self.grant_admin_override = to_raw_response_wrapper( chat.grant_admin_override, ) self.list_collaborators = to_raw_response_wrapper( chat.list_collaborators, ) + self.list_dashboards = to_raw_response_wrapper( + chat.list_dashboards, + ) + self.list_input_files = to_raw_response_wrapper( + chat.list_input_files, + ) self.list_sessions = to_raw_response_wrapper( chat.list_sessions, ) @@ -2022,6 +2625,13 @@ def __init__(self, chat: ChatResource) -> None: self.load_files = to_raw_response_wrapper( chat.load_files, ) + self.load_input_file = to_custom_raw_response_wrapper( + chat.load_input_file, + BinaryAPIResponse, + ) + self.load_input_files = to_raw_response_wrapper( + chat.load_input_files, + ) self.make_permanent = to_raw_response_wrapper( chat.make_permanent, ) @@ -2031,6 +2641,9 @@ def __init__(self, chat: ChatResource) -> None: self.revert_to_commit = to_raw_response_wrapper( chat.revert_to_commit, ) + self.simulate_prompt = to_raw_response_wrapper( + chat.simulate_prompt, + ) self.update_session = to_raw_response_wrapper( chat.update_session, ) @@ -2040,6 +2653,9 @@ def __init__(self, chat: ChatResource) -> None: self.update_visibility = to_raw_response_wrapper( chat.update_visibility, ) + self.upload_input_file = to_raw_response_wrapper( + chat.upload_input_file, + ) class AsyncChatResourceWithRawResponse: @@ -2052,12 +2668,12 @@ def __init__(self, chat: AsyncChatResource) -> None: self.add_git_commit = async_to_raw_response_wrapper( chat.add_git_commit, ) - self.admin_get_chat_prompt = async_to_raw_response_wrapper( - chat.admin_get_chat_prompt, - ) self.admin_issue_found = async_to_raw_response_wrapper( chat.admin_issue_found, ) + self.compress = async_to_raw_response_wrapper( + chat.compress, + ) self.copy = async_to_raw_response_wrapper( chat.copy, ) @@ -2067,8 +2683,8 @@ def __init__(self, chat: AsyncChatResource) -> None: self.create_session = async_to_raw_response_wrapper( chat.create_session, ) - self.delete_files = async_to_raw_response_wrapper( - chat.delete_files, + self.delete_input_file = async_to_raw_response_wrapper( + chat.delete_input_file, ) self.delete_session = async_to_raw_response_wrapper( chat.delete_session, @@ -2088,12 +2704,21 @@ def __init__(self, chat: AsyncChatResource) -> None: self.get_session_timeline = async_to_raw_response_wrapper( chat.get_session_timeline, ) + self.get_template = async_to_raw_response_wrapper( + chat.get_template, + ) self.grant_admin_override = async_to_raw_response_wrapper( chat.grant_admin_override, ) self.list_collaborators = async_to_raw_response_wrapper( chat.list_collaborators, ) + self.list_dashboards = async_to_raw_response_wrapper( + chat.list_dashboards, + ) + self.list_input_files = async_to_raw_response_wrapper( + chat.list_input_files, + ) self.list_sessions = async_to_raw_response_wrapper( chat.list_sessions, ) @@ -2103,6 +2728,13 @@ def __init__(self, chat: AsyncChatResource) -> None: self.load_files = async_to_raw_response_wrapper( chat.load_files, ) + self.load_input_file = async_to_custom_raw_response_wrapper( + chat.load_input_file, + AsyncBinaryAPIResponse, + ) + self.load_input_files = async_to_raw_response_wrapper( + chat.load_input_files, + ) self.make_permanent = async_to_raw_response_wrapper( chat.make_permanent, ) @@ -2112,6 +2744,9 @@ def __init__(self, chat: AsyncChatResource) -> None: self.revert_to_commit = async_to_raw_response_wrapper( chat.revert_to_commit, ) + self.simulate_prompt = async_to_raw_response_wrapper( + chat.simulate_prompt, + ) self.update_session = async_to_raw_response_wrapper( chat.update_session, ) @@ -2121,6 +2756,9 @@ def __init__(self, chat: AsyncChatResource) -> None: self.update_visibility = async_to_raw_response_wrapper( chat.update_visibility, ) + self.upload_input_file = async_to_raw_response_wrapper( + chat.upload_input_file, + ) class ChatResourceWithStreamingResponse: @@ -2133,12 +2771,12 @@ def __init__(self, chat: ChatResource) -> None: self.add_git_commit = to_streamed_response_wrapper( chat.add_git_commit, ) - self.admin_get_chat_prompt = to_streamed_response_wrapper( - chat.admin_get_chat_prompt, - ) self.admin_issue_found = to_streamed_response_wrapper( chat.admin_issue_found, ) + self.compress = to_streamed_response_wrapper( + chat.compress, + ) self.copy = to_streamed_response_wrapper( chat.copy, ) @@ -2148,8 +2786,8 @@ def __init__(self, chat: ChatResource) -> None: self.create_session = to_streamed_response_wrapper( chat.create_session, ) - self.delete_files = to_streamed_response_wrapper( - chat.delete_files, + self.delete_input_file = to_streamed_response_wrapper( + chat.delete_input_file, ) self.delete_session = to_streamed_response_wrapper( chat.delete_session, @@ -2169,12 +2807,21 @@ def __init__(self, chat: ChatResource) -> None: self.get_session_timeline = to_streamed_response_wrapper( chat.get_session_timeline, ) + self.get_template = to_streamed_response_wrapper( + chat.get_template, + ) self.grant_admin_override = to_streamed_response_wrapper( chat.grant_admin_override, ) self.list_collaborators = to_streamed_response_wrapper( chat.list_collaborators, ) + self.list_dashboards = to_streamed_response_wrapper( + chat.list_dashboards, + ) + self.list_input_files = to_streamed_response_wrapper( + chat.list_input_files, + ) self.list_sessions = to_streamed_response_wrapper( chat.list_sessions, ) @@ -2184,6 +2831,13 @@ def __init__(self, chat: ChatResource) -> None: self.load_files = to_streamed_response_wrapper( chat.load_files, ) + self.load_input_file = to_custom_streamed_response_wrapper( + chat.load_input_file, + StreamedBinaryAPIResponse, + ) + self.load_input_files = to_streamed_response_wrapper( + chat.load_input_files, + ) self.make_permanent = to_streamed_response_wrapper( chat.make_permanent, ) @@ -2193,6 +2847,9 @@ def __init__(self, chat: ChatResource) -> None: self.revert_to_commit = to_streamed_response_wrapper( chat.revert_to_commit, ) + self.simulate_prompt = to_streamed_response_wrapper( + chat.simulate_prompt, + ) self.update_session = to_streamed_response_wrapper( chat.update_session, ) @@ -2202,6 +2859,9 @@ def __init__(self, chat: ChatResource) -> None: self.update_visibility = to_streamed_response_wrapper( chat.update_visibility, ) + self.upload_input_file = to_streamed_response_wrapper( + chat.upload_input_file, + ) class AsyncChatResourceWithStreamingResponse: @@ -2214,12 +2874,12 @@ def __init__(self, chat: AsyncChatResource) -> None: self.add_git_commit = async_to_streamed_response_wrapper( chat.add_git_commit, ) - self.admin_get_chat_prompt = async_to_streamed_response_wrapper( - chat.admin_get_chat_prompt, - ) self.admin_issue_found = async_to_streamed_response_wrapper( chat.admin_issue_found, ) + self.compress = async_to_streamed_response_wrapper( + chat.compress, + ) self.copy = async_to_streamed_response_wrapper( chat.copy, ) @@ -2229,8 +2889,8 @@ def __init__(self, chat: AsyncChatResource) -> None: self.create_session = async_to_streamed_response_wrapper( chat.create_session, ) - self.delete_files = async_to_streamed_response_wrapper( - chat.delete_files, + self.delete_input_file = async_to_streamed_response_wrapper( + chat.delete_input_file, ) self.delete_session = async_to_streamed_response_wrapper( chat.delete_session, @@ -2250,12 +2910,21 @@ def __init__(self, chat: AsyncChatResource) -> None: self.get_session_timeline = async_to_streamed_response_wrapper( chat.get_session_timeline, ) + self.get_template = async_to_streamed_response_wrapper( + chat.get_template, + ) self.grant_admin_override = async_to_streamed_response_wrapper( chat.grant_admin_override, ) self.list_collaborators = async_to_streamed_response_wrapper( chat.list_collaborators, ) + self.list_dashboards = async_to_streamed_response_wrapper( + chat.list_dashboards, + ) + self.list_input_files = async_to_streamed_response_wrapper( + chat.list_input_files, + ) self.list_sessions = async_to_streamed_response_wrapper( chat.list_sessions, ) @@ -2265,6 +2934,13 @@ def __init__(self, chat: AsyncChatResource) -> None: self.load_files = async_to_streamed_response_wrapper( chat.load_files, ) + self.load_input_file = async_to_custom_streamed_response_wrapper( + chat.load_input_file, + AsyncStreamedBinaryAPIResponse, + ) + self.load_input_files = async_to_streamed_response_wrapper( + chat.load_input_files, + ) self.make_permanent = async_to_streamed_response_wrapper( chat.make_permanent, ) @@ -2274,6 +2950,9 @@ def __init__(self, chat: AsyncChatResource) -> None: self.revert_to_commit = async_to_streamed_response_wrapper( chat.revert_to_commit, ) + self.simulate_prompt = async_to_streamed_response_wrapper( + chat.simulate_prompt, + ) self.update_session = async_to_streamed_response_wrapper( chat.update_session, ) @@ -2283,3 +2962,6 @@ def __init__(self, chat: AsyncChatResource) -> None: self.update_visibility = async_to_streamed_response_wrapper( chat.update_visibility, ) + self.upload_input_file = async_to_streamed_response_wrapper( + chat.upload_input_file, + ) diff --git a/src/structify/resources/code.py b/src/structify/resources/code.py index 8db099382..016dfa512 100644 --- a/src/structify/resources/code.py +++ b/src/structify/resources/code.py @@ -6,9 +6,9 @@ import httpx -from ..types import code_generate_code_params, code_interrupt_generation_params +from ..types import code_generate_code_params, code_apply_manual_edit_params, code_interrupt_generation_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -23,6 +23,8 @@ class CodeResource(SyncAPIResource): + """Code generation endpoints""" + @cached_property def with_raw_response(self) -> CodeResourceWithRawResponse: """ @@ -42,6 +44,47 @@ def with_streaming_response(self) -> CodeResourceWithStreamingResponse: """ return CodeResourceWithStreamingResponse(self) + def apply_manual_edit( + self, + chat_id: str, + *, + code: str, + filename: 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, + ) -> None: + """ + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template("/code/apply-manual-edit/{chat_id}", chat_id=chat_id), + body=maybe_transform( + { + "code": code, + "filename": filename, + }, + code_apply_manual_edit_params.CodeApplyManualEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + def generate_code( self, *, @@ -138,6 +181,8 @@ def interrupt_generation( class AsyncCodeResource(AsyncAPIResource): + """Code generation endpoints""" + @cached_property def with_raw_response(self) -> AsyncCodeResourceWithRawResponse: """ @@ -157,6 +202,47 @@ def with_streaming_response(self) -> AsyncCodeResourceWithStreamingResponse: """ return AsyncCodeResourceWithStreamingResponse(self) + async def apply_manual_edit( + self, + chat_id: str, + *, + code: str, + filename: 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, + ) -> None: + """ + 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 + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template("/code/apply-manual-edit/{chat_id}", chat_id=chat_id), + body=await async_maybe_transform( + { + "code": code, + "filename": filename, + }, + code_apply_manual_edit_params.CodeApplyManualEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + async def generate_code( self, *, @@ -256,6 +342,9 @@ class CodeResourceWithRawResponse: def __init__(self, code: CodeResource) -> None: self._code = code + self.apply_manual_edit = to_raw_response_wrapper( + code.apply_manual_edit, + ) self.generate_code = to_raw_response_wrapper( code.generate_code, ) @@ -268,6 +357,9 @@ class AsyncCodeResourceWithRawResponse: def __init__(self, code: AsyncCodeResource) -> None: self._code = code + self.apply_manual_edit = async_to_raw_response_wrapper( + code.apply_manual_edit, + ) self.generate_code = async_to_raw_response_wrapper( code.generate_code, ) @@ -280,6 +372,9 @@ class CodeResourceWithStreamingResponse: def __init__(self, code: CodeResource) -> None: self._code = code + self.apply_manual_edit = to_streamed_response_wrapper( + code.apply_manual_edit, + ) self.generate_code = to_streamed_response_wrapper( code.generate_code, ) @@ -292,6 +387,9 @@ class AsyncCodeResourceWithStreamingResponse: def __init__(self, code: AsyncCodeResource) -> None: self._code = code + self.apply_manual_edit = async_to_streamed_response_wrapper( + code.apply_manual_edit, + ) self.generate_code = async_to_streamed_response_wrapper( code.generate_code, ) diff --git a/src/structify/resources/connector_catalog/admin.py b/src/structify/resources/connector_catalog/admin.py index 8469388d6..fb245fc6c 100644 --- a/src/structify/resources/connector_catalog/admin.py +++ b/src/structify/resources/connector_catalog/admin.py @@ -19,7 +19,7 @@ omit, not_given, ) -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -61,6 +61,8 @@ class AdminResource(SyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AdminResourceWithRawResponse: """ @@ -198,6 +200,8 @@ def create_catalog( slug: str, categories: SequenceNotStr[str] | Omit = omit, description: Optional[str] | Omit = omit, + enterprise_only: bool | Omit = omit, + onboarding_priority: Optional[int] | Omit = omit, priority: Optional[int] | Omit = omit, # 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. @@ -226,6 +230,8 @@ def create_catalog( "slug": slug, "categories": categories, "description": description, + "enterprise_only": enterprise_only, + "onboarding_priority": onboarding_priority, "priority": priority, }, admin_create_catalog_params.AdminCreateCatalogParams, @@ -357,7 +363,7 @@ def delete_catalog( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/admin/connector-catalog/{id}", + path_template("/admin/connector-catalog/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -391,7 +397,7 @@ def delete_credential_field( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/admin/connector-catalog/credential-fields/{id}", + path_template("/admin/connector-catalog/credential-fields/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -423,7 +429,7 @@ def delete_scope( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/admin/connector-catalog/scopes/{id}", + path_template("/admin/connector-catalog/scopes/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -514,7 +520,7 @@ def update_auth_method( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._patch( - f"/admin/connector-catalog/auth-methods/{id}", + path_template("/admin/connector-catalog/auth-methods/{id}", id=id), body=maybe_transform( { "is_active": is_active, @@ -535,7 +541,9 @@ def update_catalog( *, categories: Optional[SequenceNotStr[str]] | Omit = omit, description: Optional[str] | Omit = omit, + enterprise_only: Optional[bool] | Omit = omit, name: Optional[str] | Omit = omit, + onboarding_priority: Optional[int] | Omit = omit, priority: Optional[int] | Omit = omit, # 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. @@ -559,12 +567,14 @@ def update_catalog( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._patch( - f"/admin/connector-catalog/{id}", + path_template("/admin/connector-catalog/{id}", id=id), body=maybe_transform( { "categories": categories, "description": description, + "enterprise_only": enterprise_only, "name": name, + "onboarding_priority": onboarding_priority, "priority": priority, }, admin_update_catalog_params.AdminUpdateCatalogParams, @@ -609,7 +619,7 @@ def update_credential_field( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._patch( - f"/admin/connector-catalog/credential-fields/{id}", + path_template("/admin/connector-catalog/credential-fields/{id}", id=id), body=maybe_transform( { "default_value": default_value, @@ -657,7 +667,7 @@ def update_scope( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._patch( - f"/admin/connector-catalog/scopes/{id}", + path_template("/admin/connector-catalog/scopes/{id}", id=id), body=maybe_transform( { "is_recommended": is_recommended, @@ -704,7 +714,7 @@ def upload_logo( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._put( - f"/admin/connector-catalog/{slug}/logo", + path_template("/admin/connector-catalog/{slug}/logo", slug=slug), body=maybe_transform(body, admin_upload_logo_params.AdminUploadLogoParams), files=files, options=make_request_options( @@ -715,6 +725,8 @@ def upload_logo( class AsyncAdminResource(AsyncAPIResource): + """Admin endpoints""" + @cached_property def with_raw_response(self) -> AsyncAdminResourceWithRawResponse: """ @@ -854,6 +866,8 @@ async def create_catalog( slug: str, categories: SequenceNotStr[str] | Omit = omit, description: Optional[str] | Omit = omit, + enterprise_only: bool | Omit = omit, + onboarding_priority: Optional[int] | Omit = omit, priority: Optional[int] | Omit = omit, # 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. @@ -882,6 +896,8 @@ async def create_catalog( "slug": slug, "categories": categories, "description": description, + "enterprise_only": enterprise_only, + "onboarding_priority": onboarding_priority, "priority": priority, }, admin_create_catalog_params.AdminCreateCatalogParams, @@ -1013,7 +1029,7 @@ async def delete_catalog( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/admin/connector-catalog/{id}", + path_template("/admin/connector-catalog/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1047,7 +1063,7 @@ async def delete_credential_field( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/admin/connector-catalog/credential-fields/{id}", + path_template("/admin/connector-catalog/credential-fields/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1079,7 +1095,7 @@ async def delete_scope( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/admin/connector-catalog/scopes/{id}", + path_template("/admin/connector-catalog/scopes/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1170,7 +1186,7 @@ async def update_auth_method( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._patch( - f"/admin/connector-catalog/auth-methods/{id}", + path_template("/admin/connector-catalog/auth-methods/{id}", id=id), body=await async_maybe_transform( { "is_active": is_active, @@ -1191,7 +1207,9 @@ async def update_catalog( *, categories: Optional[SequenceNotStr[str]] | Omit = omit, description: Optional[str] | Omit = omit, + enterprise_only: Optional[bool] | Omit = omit, name: Optional[str] | Omit = omit, + onboarding_priority: Optional[int] | Omit = omit, priority: Optional[int] | Omit = omit, # 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. @@ -1215,12 +1233,14 @@ async def update_catalog( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._patch( - f"/admin/connector-catalog/{id}", + path_template("/admin/connector-catalog/{id}", id=id), body=await async_maybe_transform( { "categories": categories, "description": description, + "enterprise_only": enterprise_only, "name": name, + "onboarding_priority": onboarding_priority, "priority": priority, }, admin_update_catalog_params.AdminUpdateCatalogParams, @@ -1265,7 +1285,7 @@ async def update_credential_field( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._patch( - f"/admin/connector-catalog/credential-fields/{id}", + path_template("/admin/connector-catalog/credential-fields/{id}", id=id), body=await async_maybe_transform( { "default_value": default_value, @@ -1313,7 +1333,7 @@ async def update_scope( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._patch( - f"/admin/connector-catalog/scopes/{id}", + path_template("/admin/connector-catalog/scopes/{id}", id=id), body=await async_maybe_transform( { "is_recommended": is_recommended, @@ -1360,7 +1380,7 @@ async def upload_logo( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._put( - f"/admin/connector-catalog/{slug}/logo", + path_template("/admin/connector-catalog/{slug}/logo", slug=slug), body=await async_maybe_transform(body, admin_upload_logo_params.AdminUploadLogoParams), files=files, options=make_request_options( diff --git a/src/structify/resources/connector_catalog/connector_catalog.py b/src/structify/resources/connector_catalog/connector_catalog.py index 955bd4e15..a549b5b1f 100644 --- a/src/structify/resources/connector_catalog/connector_catalog.py +++ b/src/structify/resources/connector_catalog/connector_catalog.py @@ -15,8 +15,8 @@ AsyncAdminResourceWithStreamingResponse, ) from ...types import connector_catalog_list_params -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -43,6 +43,7 @@ class ConnectorCatalogResource(SyncAPIResource): @cached_property def admin(self) -> AdminResource: + """Admin endpoints""" return AdminResource(self._client) @cached_property @@ -67,6 +68,7 @@ def with_streaming_response(self) -> ConnectorCatalogResourceWithStreamingRespon def list( self, *, + categories: SequenceNotStr[str] | Omit = omit, include_inactive: bool | Omit = omit, limit: int | Omit = omit, offset: int | Omit = omit, @@ -82,6 +84,9 @@ def list( List all connector catalog entries with their auth methods and logos Args: + categories: Optional category filter (exact match against any element in the categories + array) + include_inactive: Include inactive auth methods (admin only) search: Optional search query to filter by name, slug, or category (case-insensitive @@ -104,6 +109,7 @@ def list( timeout=timeout, query=maybe_transform( { + "categories": categories, "include_inactive": include_inactive, "limit": limit, "offset": offset, @@ -141,7 +147,7 @@ def get( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return self._get( - f"/connector-catalog/{slug}", + path_template("/connector-catalog/{slug}", slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -173,7 +179,7 @@ def get_logo( raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return self._get( - f"/connector-catalog/{slug}/logo", + path_template("/connector-catalog/{slug}/logo", slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -184,6 +190,7 @@ def get_logo( class AsyncConnectorCatalogResource(AsyncAPIResource): @cached_property def admin(self) -> AsyncAdminResource: + """Admin endpoints""" return AsyncAdminResource(self._client) @cached_property @@ -208,6 +215,7 @@ def with_streaming_response(self) -> AsyncConnectorCatalogResourceWithStreamingR async def list( self, *, + categories: SequenceNotStr[str] | Omit = omit, include_inactive: bool | Omit = omit, limit: int | Omit = omit, offset: int | Omit = omit, @@ -223,6 +231,9 @@ async def list( List all connector catalog entries with their auth methods and logos Args: + categories: Optional category filter (exact match against any element in the categories + array) + include_inactive: Include inactive auth methods (admin only) search: Optional search query to filter by name, slug, or category (case-insensitive @@ -245,6 +256,7 @@ async def list( timeout=timeout, query=await async_maybe_transform( { + "categories": categories, "include_inactive": include_inactive, "limit": limit, "offset": offset, @@ -282,7 +294,7 @@ async def get( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return await self._get( - f"/connector-catalog/{slug}", + path_template("/connector-catalog/{slug}", slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -314,7 +326,7 @@ async def get_logo( raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return await self._get( - f"/connector-catalog/{slug}/logo", + path_template("/connector-catalog/{slug}/logo", slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -339,6 +351,7 @@ def __init__(self, connector_catalog: ConnectorCatalogResource) -> None: @cached_property def admin(self) -> AdminResourceWithRawResponse: + """Admin endpoints""" return AdminResourceWithRawResponse(self._connector_catalog.admin) @@ -359,6 +372,7 @@ def __init__(self, connector_catalog: AsyncConnectorCatalogResource) -> None: @cached_property def admin(self) -> AsyncAdminResourceWithRawResponse: + """Admin endpoints""" return AsyncAdminResourceWithRawResponse(self._connector_catalog.admin) @@ -379,6 +393,7 @@ def __init__(self, connector_catalog: ConnectorCatalogResource) -> None: @cached_property def admin(self) -> AdminResourceWithStreamingResponse: + """Admin endpoints""" return AdminResourceWithStreamingResponse(self._connector_catalog.admin) @@ -399,4 +414,5 @@ def __init__(self, connector_catalog: AsyncConnectorCatalogResource) -> None: @cached_property def admin(self) -> AsyncAdminResourceWithStreamingResponse: + """Admin endpoints""" return AsyncAdminResourceWithStreamingResponse(self._connector_catalog.admin) diff --git a/src/structify/resources/connectors/connectors.py b/src/structify/resources/connectors/connectors.py index 4b967eaf7..b169f12fb 100644 --- a/src/structify/resources/connectors/connectors.py +++ b/src/structify/resources/connectors/connectors.py @@ -2,12 +2,13 @@ from __future__ import annotations -from typing import Any, Dict, Optional, cast +from typing import Any, Dict, Mapping, Optional, cast from typing_extensions import Literal, overload import httpx from ...types import ( + ConnectorCategory, connector_list_params, connector_create_params, connector_update_params, @@ -19,18 +20,45 @@ connector_update_column_params, connector_add_schema_object_params, connector_get_explorer_chat_params, - connector_list_with_snippets_params, connector_delete_schema_object_params, + connector_upload_datahub_artifact_params, + connector_download_datahub_artifact_params, +) +from ..._types import ( + Body, + Omit, + Query, + Headers, + NoneType, + NotGiven, + FileTypes, + SequenceNotStr, + omit, + not_given, +) +from ..._utils import ( + extract_files, + path_template, + required_args, + maybe_transform, + deepcopy_minimal, + async_maybe_transform, ) -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import required_args, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, to_raw_response_wrapper, to_streamed_response_wrapper, async_to_raw_response_wrapper, + to_custom_raw_response_wrapper, async_to_streamed_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_raw_response_wrapper, + async_to_custom_streamed_response_wrapper, ) from ...pagination import SyncJobsList, AsyncJobsList from .type_snippets import ( @@ -43,16 +71,22 @@ ) from ..._base_client import AsyncPaginator, make_request_options from ...types.connector import Connector +from ...types.exploration_run import ExplorationRun +from ...types.connector_category import ConnectorCategory +from ...types.exploration_progress import ExplorationProgress from ...types.list_tables_response import ListTablesResponse from ...types.update_table_response import UpdateTableResponse from ...types.connector_get_response import ConnectorGetResponse from ...types.connector_with_secrets import ConnectorWithSecrets from ...types.explorer_chat_response import ExplorerChatResponse -from ...types.explore_status_response import ExploreStatusResponse from ...types.connector_store_response import ConnectorStoreResponse +from ...types.datahub_secret_map_param import DatahubSecretMapParam from ...types.exploration_runs_response import ExplorationRunsResponse +from ...types.connector_explore_response import ConnectorExploreResponse from ...types.connector_summaries_response import ConnectorSummariesResponse +from ...types.connector_table_path_response import ConnectorTablePathResponse from ...types.delete_schema_object_response import DeleteSchemaObjectResponse +from ...types.connector_list_stores_response import ConnectorListStoresResponse from ...types.connector_search_tables_response import ConnectorSearchTablesResponse from ...types.connector_add_schema_object_response import ConnectorAddSchemaObjectResponse from ...types.connector_list_with_snippets_response import ConnectorListWithSnippetsResponse @@ -90,14 +124,8 @@ def create( *, known_connector_type: str, name: str, - team_id: str, description: Optional[str] | Omit = omit, nango_connection_id: Optional[str] | Omit = omit, - nango_integration_id: Optional[str] | Omit = omit, - pipedream_account_id: Optional[str] | Omit = omit, - pipedream_external_id: Optional[str] | Omit = omit, - pipedream_project_id: Optional[str] | Omit = omit, - refresh_script: Optional[str] | Omit = omit, secrets: Dict[str, str] | Omit = omit, # 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. @@ -110,10 +138,6 @@ def create( Args: nango_connection_id: Nango connection ID for OAuth token management - nango_integration_id: Nango integration ID (e.g., "linear", "slack") - - pipedream_external_id: Unique external ID for Pipedream routing (required for Pipedream connectors) - secrets: Optional secrets/environment variables for the connector extra_headers: Send extra headers @@ -130,14 +154,8 @@ def create( { "known_connector_type": known_connector_type, "name": name, - "team_id": team_id, "description": description, "nango_connection_id": nango_connection_id, - "nango_integration_id": nango_integration_id, - "pipedream_account_id": pipedream_account_id, - "pipedream_external_id": pipedream_external_id, - "pipedream_project_id": pipedream_project_id, - "refresh_script": refresh_script, "secrets": secrets, }, connector_create_params.ConnectorCreateParams, @@ -152,11 +170,20 @@ def update( self, connector_id: str, *, + connector_category: Optional[ConnectorCategory] | Omit = omit, + datahub_ingestion_type: Optional[str] | Omit = omit, + datahub_secret_map: Optional[DatahubSecretMapParam] | Omit = omit, + datahub_urn: Optional[str] | Omit = omit, description: Optional[str] | Omit = omit, known_connector_type: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, - refresh_script: Optional[str] | Omit = omit, + nango_connection_id: Optional[str] | Omit = omit, + oauth_scopes: Optional[SequenceNotStr[Optional[str]]] | Omit = omit, + owner_user_id: Optional[str] | Omit = omit, + refresh_cron_schedule: Optional[str] | Omit = omit, + team_visibility: Optional[Literal["Team", "Private"]] | Omit = omit, usage_snippet_override: Optional[str] | Omit = omit, + user_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, @@ -166,6 +193,9 @@ def update( ) -> None: """ Args: + datahub_secret_map: Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -178,14 +208,23 @@ def update( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._patch( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), body=maybe_transform( { + "connector_category": connector_category, + "datahub_ingestion_type": datahub_ingestion_type, + "datahub_secret_map": datahub_secret_map, + "datahub_urn": datahub_urn, "description": description, "known_connector_type": known_connector_type, "name": name, - "refresh_script": refresh_script, + "nango_connection_id": nango_connection_id, + "oauth_scopes": oauth_scopes, + "owner_user_id": owner_user_id, + "refresh_cron_schedule": refresh_cron_schedule, + "team_visibility": team_visibility, "usage_snippet_override": usage_snippet_override, + "user_ids": user_ids, }, connector_update_params.ConnectorUpdateParams, ), @@ -198,7 +237,6 @@ def update( def list( self, *, - team_id: str, limit: int | Omit = omit, offset: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -210,8 +248,6 @@ def list( ) -> SyncJobsList[ConnectorWithSecrets]: """ Args: - team_id: Team ID to list connectors for - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -230,7 +266,6 @@ def list( timeout=timeout, query=maybe_transform( { - "team_id": team_id, "limit": limit, "offset": offset, }, @@ -265,7 +300,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -419,7 +454,7 @@ def add_schema_object( return cast( ConnectorAddSchemaObjectResponse, self._post( - f"/connectors/{connector_id}/schema_object", + path_template("/connectors/{connector_id}/schema_object", connector_id=connector_id), body=maybe_transform( { "name": name, @@ -470,7 +505,7 @@ def create_secret( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/connectors/{connector_id}/secrets", + path_template("/connectors/{connector_id}/secrets", connector_id=connector_id), body=maybe_transform( { "secret_name": secret_name, @@ -605,7 +640,7 @@ def delete_schema_object( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._delete( - f"/connectors/{connector_id}/schema_object", + path_template("/connectors/{connector_id}/schema_object", connector_id=connector_id), body=maybe_transform( { "id": id, @@ -647,20 +682,67 @@ def delete_secret( raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/connectors/{connector_id}/secrets/{secret_name}", + path_template( + "/connectors/{connector_id}/secrets/{secret_name}", connector_id=connector_id, secret_name=secret_name + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=NoneType, ) + def download_datahub_artifact( + self, + kind: str, + *, + connector_id: str, + exploration_run_id: Optional[str] | Omit = omit, + # 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, + ) -> BinaryAPIResponse: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not kind: + raise ValueError(f"Expected a non-empty value for `kind` but received {kind!r}") + extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} + return self._get( + path_template( + "/internal/connectors/{connector_id}/datahub-artifacts/{kind}", connector_id=connector_id, kind=kind + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"exploration_run_id": exploration_run_id}, + connector_download_datahub_artifact_params.ConnectorDownloadDatahubArtifactParams, + ), + ), + cast_to=BinaryAPIResponse, + ) + def explore( self, connector_id: str, *, database_id: Optional[str] | Omit = omit, + only_do_datahub: Optional[bool] | Omit = omit, schema_id: Optional[str] | Omit = omit, - stage: Optional[Literal["both", "ingestion", "annotation"]] | Omit = omit, table_id: Optional[str] | Omit = omit, # 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. @@ -668,10 +750,10 @@ def explore( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: + ) -> ConnectorExploreResponse: """ Args: - stage: Which exploration stage to run + only_do_datahub: If true, run only DataHub ingestion without queuing Diego annotation jobs. extra_headers: Send extra headers @@ -683,14 +765,13 @@ def explore( """ if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/connectors/{connector_id}/explore", + path_template("/connectors/{connector_id}/explore", connector_id=connector_id), body=maybe_transform( { "database_id": database_id, + "only_do_datahub": only_do_datahub, "schema_id": schema_id, - "stage": stage, "table_id": table_id, }, connector_explore_params.ConnectorExploreParams, @@ -698,7 +779,7 @@ def explore( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=ConnectorExploreResponse, ) def get( @@ -725,13 +806,44 @@ def get( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorGetResponse, ) + def get_active_exploration_run( + self, + connector_id: 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, + ) -> Optional[ExplorationRun]: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + return self._get( + path_template("/connectors/{connector_id}/explore/active-run", connector_id=connector_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExplorationRun, + ) + def get_clarification_requests( self, connector_id: str, @@ -758,27 +870,26 @@ def get_clarification_requests( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}/clarification-requests", + path_template("/connectors/{connector_id}/clarification-requests", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorGetClarificationRequestsResponse, ) - def get_exploration_runs( + def get_exploration_run_progress( self, - connector_id: str, + run_id: str, *, + connector_id: 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, - ) -> ExplorationRunsResponse: + ) -> ExplorationProgress: """ - Get all exploration runs for a connector (requires debug permission) - Args: extra_headers: Send extra headers @@ -790,15 +901,19 @@ def get_exploration_runs( """ if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get( - f"/connectors/{connector_id}/explore/runs", + path_template( + "/connectors/{connector_id}/explore/runs/{run_id}/progress", connector_id=connector_id, run_id=run_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ExplorationRunsResponse, + cast_to=ExplorationProgress, ) - def get_exploration_status( + def get_exploration_runs( self, connector_id: str, *, @@ -808,8 +923,10 @@ def get_exploration_status( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ExploreStatusResponse: + ) -> ExplorationRunsResponse: """ + Get all exploration runs for a connector (requires debug permission) + Args: extra_headers: Send extra headers @@ -822,18 +939,21 @@ def get_exploration_status( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}/explore/status", + path_template("/connectors/{connector_id}/explore/runs", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ExploreStatusResponse, + cast_to=ExplorationRunsResponse, ) def get_explorer_chat( self, connector_id: str, *, - run_id: str, + database_id: Optional[str] | Omit = omit, + run_id: Optional[str] | Omit = omit, + schema_id: Optional[str] | Omit = omit, + table_id: Optional[str] | Omit = omit, # 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, @@ -842,12 +962,9 @@ def get_explorer_chat( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ExplorerChatResponse: """ - Returns chats for all phases (table discovery, column discovery for each table, - etc.) + Optionally filter by run, database, schema, or table Args: - run_id: Exploration run ID (required) - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -859,14 +976,20 @@ def get_explorer_chat( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}/explore/chat", + path_template("/connectors/{connector_id}/explore/chat", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"run_id": run_id}, connector_get_explorer_chat_params.ConnectorGetExplorerChatParams + { + "database_id": database_id, + "run_id": run_id, + "schema_id": schema_id, + "table_id": table_id, + }, + connector_get_explorer_chat_params.ConnectorGetExplorerChatParams, ), ), cast_to=ExplorerChatResponse, @@ -896,13 +1019,62 @@ def get_store( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}/store", + path_template("/connectors/{connector_id}/store", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorStoreResponse, ) + def get_table_path( + self, + table_id: 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, + ) -> ConnectorTablePathResponse: + """ + 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 + """ + if not table_id: + raise ValueError(f"Expected a non-empty value for `table_id` but received {table_id!r}") + return self._get( + path_template("/connectors/tables/{table_id}/path", table_id=table_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectorTablePathResponse, + ) + + def list_stores( + 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, + ) -> ConnectorListStoresResponse: + return self._get( + "/connectors/stores", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectorListStoresResponse, + ) + def list_tables( self, connector_id: str, @@ -931,7 +1103,7 @@ def list_tables( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return self._get( - f"/connectors/{connector_id}/tables", + path_template("/connectors/{connector_id}/tables", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -941,7 +1113,6 @@ def list_tables( def list_with_snippets( self, *, - team_id: 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, @@ -949,28 +1120,10 @@ def list_with_snippets( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConnectorListWithSnippetsResponse: - """ - Args: - team_id: Team ID to list connectors for - - 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( "/connectors/with-snippets", options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - {"team_id": team_id}, connector_list_with_snippets_params.ConnectorListWithSnippetsParams - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorListWithSnippetsResponse, ) @@ -1002,7 +1155,9 @@ def resolve_clarification( raise ValueError(f"Expected a non-empty value for `clarification_id` but received {clarification_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._patch( - f"/connectors/clarification-requests/{clarification_id}/resolve", + path_template( + "/connectors/clarification-requests/{clarification_id}/resolve", clarification_id=clarification_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1025,7 +1180,7 @@ def search_tables( Args: query: Search query string - team_id: Team ID to search tables for + team_id: Team ID to scope table search extra_headers: Send extra headers @@ -1057,7 +1212,6 @@ def summaries( self, *, connector_ids: SequenceNotStr[str], - team_id: 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, @@ -1077,13 +1231,7 @@ def summaries( """ return self._post( "/connectors/summaries", - body=maybe_transform( - { - "connector_ids": connector_ids, - "team_id": team_id, - }, - connector_summaries_params.ConnectorSummariesParams, - ), + body=maybe_transform({"connector_ids": connector_ids}, connector_summaries_params.ConnectorSummariesParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1118,7 +1266,7 @@ def update_column( raise ValueError(f"Expected a non-empty value for `column_id` but received {column_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._patch( - f"/connectors/columns/{column_id}", + path_template("/connectors/columns/{column_id}", column_id=column_id), body=maybe_transform({"notes": notes}, connector_update_column_params.ConnectorUpdateColumnParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1154,7 +1302,7 @@ def update_table( if not table_id: raise ValueError(f"Expected a non-empty value for `table_id` but received {table_id!r}") return self._patch( - f"/connectors/tables/{table_id}", + path_template("/connectors/tables/{table_id}", table_id=table_id), body=maybe_transform( { "description": description, @@ -1168,6 +1316,60 @@ def update_table( cast_to=UpdateTableResponse, ) + def upload_datahub_artifact( + self, + kind: str, + *, + connector_id: str, + exploration_run_id: str, + file: FileTypes, + # 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, + ) -> None: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not kind: + raise ValueError(f"Expected a non-empty value for `kind` but received {kind!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + body = deepcopy_minimal({"file": file}) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers["Content-Type"] = "multipart/form-data" + return self._put( + path_template( + "/internal/connectors/{connector_id}/datahub-artifacts/{kind}", connector_id=connector_id, kind=kind + ), + body=maybe_transform(body, connector_upload_datahub_artifact_params.ConnectorUploadDatahubArtifactParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"exploration_run_id": exploration_run_id}, + connector_upload_datahub_artifact_params.ConnectorUploadDatahubArtifactParams, + ), + ), + cast_to=NoneType, + ) + class AsyncConnectorsResource(AsyncAPIResource): @cached_property @@ -1198,14 +1400,8 @@ async def create( *, known_connector_type: str, name: str, - team_id: str, description: Optional[str] | Omit = omit, nango_connection_id: Optional[str] | Omit = omit, - nango_integration_id: Optional[str] | Omit = omit, - pipedream_account_id: Optional[str] | Omit = omit, - pipedream_external_id: Optional[str] | Omit = omit, - pipedream_project_id: Optional[str] | Omit = omit, - refresh_script: Optional[str] | Omit = omit, secrets: Dict[str, str] | Omit = omit, # 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. @@ -1218,10 +1414,6 @@ async def create( Args: nango_connection_id: Nango connection ID for OAuth token management - nango_integration_id: Nango integration ID (e.g., "linear", "slack") - - pipedream_external_id: Unique external ID for Pipedream routing (required for Pipedream connectors) - secrets: Optional secrets/environment variables for the connector extra_headers: Send extra headers @@ -1238,14 +1430,8 @@ async def create( { "known_connector_type": known_connector_type, "name": name, - "team_id": team_id, "description": description, "nango_connection_id": nango_connection_id, - "nango_integration_id": nango_integration_id, - "pipedream_account_id": pipedream_account_id, - "pipedream_external_id": pipedream_external_id, - "pipedream_project_id": pipedream_project_id, - "refresh_script": refresh_script, "secrets": secrets, }, connector_create_params.ConnectorCreateParams, @@ -1260,11 +1446,20 @@ async def update( self, connector_id: str, *, + connector_category: Optional[ConnectorCategory] | Omit = omit, + datahub_ingestion_type: Optional[str] | Omit = omit, + datahub_secret_map: Optional[DatahubSecretMapParam] | Omit = omit, + datahub_urn: Optional[str] | Omit = omit, description: Optional[str] | Omit = omit, known_connector_type: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, - refresh_script: Optional[str] | Omit = omit, + nango_connection_id: Optional[str] | Omit = omit, + oauth_scopes: Optional[SequenceNotStr[Optional[str]]] | Omit = omit, + owner_user_id: Optional[str] | Omit = omit, + refresh_cron_schedule: Optional[str] | Omit = omit, + team_visibility: Optional[Literal["Team", "Private"]] | Omit = omit, usage_snippet_override: Optional[str] | Omit = omit, + user_ids: Optional[SequenceNotStr[str]] | Omit = omit, # 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, @@ -1274,6 +1469,9 @@ async def update( ) -> None: """ Args: + datahub_secret_map: Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1286,14 +1484,23 @@ async def update( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._patch( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), body=await async_maybe_transform( { + "connector_category": connector_category, + "datahub_ingestion_type": datahub_ingestion_type, + "datahub_secret_map": datahub_secret_map, + "datahub_urn": datahub_urn, "description": description, "known_connector_type": known_connector_type, "name": name, - "refresh_script": refresh_script, + "nango_connection_id": nango_connection_id, + "oauth_scopes": oauth_scopes, + "owner_user_id": owner_user_id, + "refresh_cron_schedule": refresh_cron_schedule, + "team_visibility": team_visibility, "usage_snippet_override": usage_snippet_override, + "user_ids": user_ids, }, connector_update_params.ConnectorUpdateParams, ), @@ -1306,7 +1513,6 @@ async def update( def list( self, *, - team_id: str, limit: int | Omit = omit, offset: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1318,8 +1524,6 @@ def list( ) -> AsyncPaginator[ConnectorWithSecrets, AsyncJobsList[ConnectorWithSecrets]]: """ Args: - team_id: Team ID to list connectors for - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1338,7 +1542,6 @@ def list( timeout=timeout, query=maybe_transform( { - "team_id": team_id, "limit": limit, "offset": offset, }, @@ -1373,7 +1576,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1527,7 +1730,7 @@ async def add_schema_object( return cast( ConnectorAddSchemaObjectResponse, await self._post( - f"/connectors/{connector_id}/schema_object", + path_template("/connectors/{connector_id}/schema_object", connector_id=connector_id), body=await async_maybe_transform( { "name": name, @@ -1578,7 +1781,7 @@ async def create_secret( raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/connectors/{connector_id}/secrets", + path_template("/connectors/{connector_id}/secrets", connector_id=connector_id), body=await async_maybe_transform( { "secret_name": secret_name, @@ -1713,7 +1916,7 @@ async def delete_schema_object( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._delete( - f"/connectors/{connector_id}/schema_object", + path_template("/connectors/{connector_id}/schema_object", connector_id=connector_id), body=await async_maybe_transform( { "id": id, @@ -1755,20 +1958,67 @@ async def delete_secret( raise ValueError(f"Expected a non-empty value for `secret_name` but received {secret_name!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/connectors/{connector_id}/secrets/{secret_name}", + path_template( + "/connectors/{connector_id}/secrets/{secret_name}", connector_id=connector_id, secret_name=secret_name + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=NoneType, ) + async def download_datahub_artifact( + self, + kind: str, + *, + connector_id: str, + exploration_run_id: Optional[str] | Omit = omit, + # 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, + ) -> AsyncBinaryAPIResponse: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not kind: + raise ValueError(f"Expected a non-empty value for `kind` but received {kind!r}") + extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} + return await self._get( + path_template( + "/internal/connectors/{connector_id}/datahub-artifacts/{kind}", connector_id=connector_id, kind=kind + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"exploration_run_id": exploration_run_id}, + connector_download_datahub_artifact_params.ConnectorDownloadDatahubArtifactParams, + ), + ), + cast_to=AsyncBinaryAPIResponse, + ) + async def explore( self, connector_id: str, *, database_id: Optional[str] | Omit = omit, + only_do_datahub: Optional[bool] | Omit = omit, schema_id: Optional[str] | Omit = omit, - stage: Optional[Literal["both", "ingestion", "annotation"]] | Omit = omit, table_id: Optional[str] | Omit = omit, # 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. @@ -1776,10 +2026,10 @@ async def explore( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: + ) -> ConnectorExploreResponse: """ Args: - stage: Which exploration stage to run + only_do_datahub: If true, run only DataHub ingestion without queuing Diego annotation jobs. extra_headers: Send extra headers @@ -1791,14 +2041,13 @@ async def explore( """ if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/connectors/{connector_id}/explore", + path_template("/connectors/{connector_id}/explore", connector_id=connector_id), body=await async_maybe_transform( { "database_id": database_id, + "only_do_datahub": only_do_datahub, "schema_id": schema_id, - "stage": stage, "table_id": table_id, }, connector_explore_params.ConnectorExploreParams, @@ -1806,7 +2055,7 @@ async def explore( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=NoneType, + cast_to=ConnectorExploreResponse, ) async def get( @@ -1833,13 +2082,44 @@ async def get( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}", + path_template("/connectors/{connector_id}", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorGetResponse, ) + async def get_active_exploration_run( + self, + connector_id: 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, + ) -> Optional[ExplorationRun]: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + return await self._get( + path_template("/connectors/{connector_id}/explore/active-run", connector_id=connector_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExplorationRun, + ) + async def get_clarification_requests( self, connector_id: str, @@ -1866,27 +2146,26 @@ async def get_clarification_requests( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}/clarification-requests", + path_template("/connectors/{connector_id}/clarification-requests", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorGetClarificationRequestsResponse, ) - async def get_exploration_runs( + async def get_exploration_run_progress( self, - connector_id: str, + run_id: str, *, + connector_id: 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, - ) -> ExplorationRunsResponse: + ) -> ExplorationProgress: """ - Get all exploration runs for a connector (requires debug permission) - Args: extra_headers: Send extra headers @@ -1898,15 +2177,19 @@ async def get_exploration_runs( """ if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not run_id: + raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._get( - f"/connectors/{connector_id}/explore/runs", + path_template( + "/connectors/{connector_id}/explore/runs/{run_id}/progress", connector_id=connector_id, run_id=run_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ExplorationRunsResponse, + cast_to=ExplorationProgress, ) - async def get_exploration_status( + async def get_exploration_runs( self, connector_id: str, *, @@ -1916,8 +2199,10 @@ async def get_exploration_status( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ExploreStatusResponse: + ) -> ExplorationRunsResponse: """ + Get all exploration runs for a connector (requires debug permission) + Args: extra_headers: Send extra headers @@ -1930,18 +2215,21 @@ async def get_exploration_status( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}/explore/status", + path_template("/connectors/{connector_id}/explore/runs", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ExploreStatusResponse, + cast_to=ExplorationRunsResponse, ) async def get_explorer_chat( self, connector_id: str, *, - run_id: str, + database_id: Optional[str] | Omit = omit, + run_id: Optional[str] | Omit = omit, + schema_id: Optional[str] | Omit = omit, + table_id: Optional[str] | Omit = omit, # 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, @@ -1950,12 +2238,9 @@ async def get_explorer_chat( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ExplorerChatResponse: """ - Returns chats for all phases (table discovery, column discovery for each table, - etc.) + Optionally filter by run, database, schema, or table Args: - run_id: Exploration run ID (required) - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1967,14 +2252,20 @@ async def get_explorer_chat( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}/explore/chat", + path_template("/connectors/{connector_id}/explore/chat", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"run_id": run_id}, connector_get_explorer_chat_params.ConnectorGetExplorerChatParams + { + "database_id": database_id, + "run_id": run_id, + "schema_id": schema_id, + "table_id": table_id, + }, + connector_get_explorer_chat_params.ConnectorGetExplorerChatParams, ), ), cast_to=ExplorerChatResponse, @@ -2004,13 +2295,62 @@ async def get_store( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}/store", + path_template("/connectors/{connector_id}/store", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorStoreResponse, ) + async def get_table_path( + self, + table_id: 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, + ) -> ConnectorTablePathResponse: + """ + 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 + """ + if not table_id: + raise ValueError(f"Expected a non-empty value for `table_id` but received {table_id!r}") + return await self._get( + path_template("/connectors/tables/{table_id}/path", table_id=table_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectorTablePathResponse, + ) + + async def list_stores( + 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, + ) -> ConnectorListStoresResponse: + return await self._get( + "/connectors/stores", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConnectorListStoresResponse, + ) + async def list_tables( self, connector_id: str, @@ -2039,7 +2379,7 @@ async def list_tables( if not connector_id: raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") return await self._get( - f"/connectors/{connector_id}/tables", + path_template("/connectors/{connector_id}/tables", connector_id=connector_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2049,7 +2389,6 @@ async def list_tables( async def list_with_snippets( self, *, - team_id: 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, @@ -2057,28 +2396,10 @@ async def list_with_snippets( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConnectorListWithSnippetsResponse: - """ - Args: - team_id: Team ID to list connectors for - - 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( "/connectors/with-snippets", options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"team_id": team_id}, connector_list_with_snippets_params.ConnectorListWithSnippetsParams - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=ConnectorListWithSnippetsResponse, ) @@ -2110,7 +2431,9 @@ async def resolve_clarification( raise ValueError(f"Expected a non-empty value for `clarification_id` but received {clarification_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._patch( - f"/connectors/clarification-requests/{clarification_id}/resolve", + path_template( + "/connectors/clarification-requests/{clarification_id}/resolve", clarification_id=clarification_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2133,7 +2456,7 @@ async def search_tables( Args: query: Search query string - team_id: Team ID to search tables for + team_id: Team ID to scope table search extra_headers: Send extra headers @@ -2165,7 +2488,6 @@ async def summaries( self, *, connector_ids: SequenceNotStr[str], - team_id: 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, @@ -2186,11 +2508,7 @@ async def summaries( return await self._post( "/connectors/summaries", body=await async_maybe_transform( - { - "connector_ids": connector_ids, - "team_id": team_id, - }, - connector_summaries_params.ConnectorSummariesParams, + {"connector_ids": connector_ids}, connector_summaries_params.ConnectorSummariesParams ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2226,7 +2544,7 @@ async def update_column( raise ValueError(f"Expected a non-empty value for `column_id` but received {column_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._patch( - f"/connectors/columns/{column_id}", + path_template("/connectors/columns/{column_id}", column_id=column_id), body=await async_maybe_transform( {"notes": notes}, connector_update_column_params.ConnectorUpdateColumnParams ), @@ -2264,7 +2582,7 @@ async def update_table( if not table_id: raise ValueError(f"Expected a non-empty value for `table_id` but received {table_id!r}") return await self._patch( - f"/connectors/tables/{table_id}", + path_template("/connectors/tables/{table_id}", table_id=table_id), body=await async_maybe_transform( { "description": description, @@ -2278,6 +2596,62 @@ async def update_table( cast_to=UpdateTableResponse, ) + async def upload_datahub_artifact( + self, + kind: str, + *, + connector_id: str, + exploration_run_id: str, + file: FileTypes, + # 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, + ) -> None: + """ + 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 + """ + if not connector_id: + raise ValueError(f"Expected a non-empty value for `connector_id` but received {connector_id!r}") + if not kind: + raise ValueError(f"Expected a non-empty value for `kind` but received {kind!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + body = deepcopy_minimal({"file": file}) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers["Content-Type"] = "multipart/form-data" + return await self._put( + path_template( + "/internal/connectors/{connector_id}/datahub-artifacts/{kind}", connector_id=connector_id, kind=kind + ), + body=await async_maybe_transform( + body, connector_upload_datahub_artifact_params.ConnectorUploadDatahubArtifactParams + ), + files=files, + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"exploration_run_id": exploration_run_id}, + connector_upload_datahub_artifact_params.ConnectorUploadDatahubArtifactParams, + ), + ), + cast_to=NoneType, + ) + class ConnectorsResourceWithRawResponse: def __init__(self, connectors: ConnectorsResource) -> None: @@ -2307,27 +2681,40 @@ def __init__(self, connectors: ConnectorsResource) -> None: self.delete_secret = to_raw_response_wrapper( connectors.delete_secret, ) + self.download_datahub_artifact = to_custom_raw_response_wrapper( + connectors.download_datahub_artifact, + BinaryAPIResponse, + ) self.explore = to_raw_response_wrapper( connectors.explore, ) self.get = to_raw_response_wrapper( connectors.get, ) + self.get_active_exploration_run = to_raw_response_wrapper( + connectors.get_active_exploration_run, + ) self.get_clarification_requests = to_raw_response_wrapper( connectors.get_clarification_requests, ) + self.get_exploration_run_progress = to_raw_response_wrapper( + connectors.get_exploration_run_progress, + ) self.get_exploration_runs = to_raw_response_wrapper( connectors.get_exploration_runs, ) - self.get_exploration_status = to_raw_response_wrapper( - connectors.get_exploration_status, - ) self.get_explorer_chat = to_raw_response_wrapper( connectors.get_explorer_chat, ) self.get_store = to_raw_response_wrapper( connectors.get_store, ) + self.get_table_path = to_raw_response_wrapper( + connectors.get_table_path, + ) + self.list_stores = to_raw_response_wrapper( + connectors.list_stores, + ) self.list_tables = to_raw_response_wrapper( connectors.list_tables, ) @@ -2349,6 +2736,9 @@ def __init__(self, connectors: ConnectorsResource) -> None: self.update_table = to_raw_response_wrapper( connectors.update_table, ) + self.upload_datahub_artifact = to_raw_response_wrapper( + connectors.upload_datahub_artifact, + ) @cached_property def type_snippets(self) -> TypeSnippetsResourceWithRawResponse: @@ -2383,27 +2773,40 @@ def __init__(self, connectors: AsyncConnectorsResource) -> None: self.delete_secret = async_to_raw_response_wrapper( connectors.delete_secret, ) + self.download_datahub_artifact = async_to_custom_raw_response_wrapper( + connectors.download_datahub_artifact, + AsyncBinaryAPIResponse, + ) self.explore = async_to_raw_response_wrapper( connectors.explore, ) self.get = async_to_raw_response_wrapper( connectors.get, ) + self.get_active_exploration_run = async_to_raw_response_wrapper( + connectors.get_active_exploration_run, + ) self.get_clarification_requests = async_to_raw_response_wrapper( connectors.get_clarification_requests, ) + self.get_exploration_run_progress = async_to_raw_response_wrapper( + connectors.get_exploration_run_progress, + ) self.get_exploration_runs = async_to_raw_response_wrapper( connectors.get_exploration_runs, ) - self.get_exploration_status = async_to_raw_response_wrapper( - connectors.get_exploration_status, - ) self.get_explorer_chat = async_to_raw_response_wrapper( connectors.get_explorer_chat, ) self.get_store = async_to_raw_response_wrapper( connectors.get_store, ) + self.get_table_path = async_to_raw_response_wrapper( + connectors.get_table_path, + ) + self.list_stores = async_to_raw_response_wrapper( + connectors.list_stores, + ) self.list_tables = async_to_raw_response_wrapper( connectors.list_tables, ) @@ -2425,6 +2828,9 @@ def __init__(self, connectors: AsyncConnectorsResource) -> None: self.update_table = async_to_raw_response_wrapper( connectors.update_table, ) + self.upload_datahub_artifact = async_to_raw_response_wrapper( + connectors.upload_datahub_artifact, + ) @cached_property def type_snippets(self) -> AsyncTypeSnippetsResourceWithRawResponse: @@ -2459,27 +2865,40 @@ def __init__(self, connectors: ConnectorsResource) -> None: self.delete_secret = to_streamed_response_wrapper( connectors.delete_secret, ) + self.download_datahub_artifact = to_custom_streamed_response_wrapper( + connectors.download_datahub_artifact, + StreamedBinaryAPIResponse, + ) self.explore = to_streamed_response_wrapper( connectors.explore, ) self.get = to_streamed_response_wrapper( connectors.get, ) + self.get_active_exploration_run = to_streamed_response_wrapper( + connectors.get_active_exploration_run, + ) self.get_clarification_requests = to_streamed_response_wrapper( connectors.get_clarification_requests, ) + self.get_exploration_run_progress = to_streamed_response_wrapper( + connectors.get_exploration_run_progress, + ) self.get_exploration_runs = to_streamed_response_wrapper( connectors.get_exploration_runs, ) - self.get_exploration_status = to_streamed_response_wrapper( - connectors.get_exploration_status, - ) self.get_explorer_chat = to_streamed_response_wrapper( connectors.get_explorer_chat, ) self.get_store = to_streamed_response_wrapper( connectors.get_store, ) + self.get_table_path = to_streamed_response_wrapper( + connectors.get_table_path, + ) + self.list_stores = to_streamed_response_wrapper( + connectors.list_stores, + ) self.list_tables = to_streamed_response_wrapper( connectors.list_tables, ) @@ -2501,6 +2920,9 @@ def __init__(self, connectors: ConnectorsResource) -> None: self.update_table = to_streamed_response_wrapper( connectors.update_table, ) + self.upload_datahub_artifact = to_streamed_response_wrapper( + connectors.upload_datahub_artifact, + ) @cached_property def type_snippets(self) -> TypeSnippetsResourceWithStreamingResponse: @@ -2535,27 +2957,40 @@ def __init__(self, connectors: AsyncConnectorsResource) -> None: self.delete_secret = async_to_streamed_response_wrapper( connectors.delete_secret, ) + self.download_datahub_artifact = async_to_custom_streamed_response_wrapper( + connectors.download_datahub_artifact, + AsyncStreamedBinaryAPIResponse, + ) self.explore = async_to_streamed_response_wrapper( connectors.explore, ) self.get = async_to_streamed_response_wrapper( connectors.get, ) + self.get_active_exploration_run = async_to_streamed_response_wrapper( + connectors.get_active_exploration_run, + ) self.get_clarification_requests = async_to_streamed_response_wrapper( connectors.get_clarification_requests, ) + self.get_exploration_run_progress = async_to_streamed_response_wrapper( + connectors.get_exploration_run_progress, + ) self.get_exploration_runs = async_to_streamed_response_wrapper( connectors.get_exploration_runs, ) - self.get_exploration_status = async_to_streamed_response_wrapper( - connectors.get_exploration_status, - ) self.get_explorer_chat = async_to_streamed_response_wrapper( connectors.get_explorer_chat, ) self.get_store = async_to_streamed_response_wrapper( connectors.get_store, ) + self.get_table_path = async_to_streamed_response_wrapper( + connectors.get_table_path, + ) + self.list_stores = async_to_streamed_response_wrapper( + connectors.list_stores, + ) self.list_tables = async_to_streamed_response_wrapper( connectors.list_tables, ) @@ -2577,6 +3012,9 @@ def __init__(self, connectors: AsyncConnectorsResource) -> None: self.update_table = async_to_streamed_response_wrapper( connectors.update_table, ) + self.upload_datahub_artifact = async_to_streamed_response_wrapper( + connectors.upload_datahub_artifact, + ) @cached_property def type_snippets(self) -> AsyncTypeSnippetsResourceWithStreamingResponse: diff --git a/src/structify/resources/connectors/type_snippets.py b/src/structify/resources/connectors/type_snippets.py index 84a1b11a1..d7f8bb234 100644 --- a/src/structify/resources/connectors/type_snippets.py +++ b/src/structify/resources/connectors/type_snippets.py @@ -7,7 +7,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -68,7 +68,7 @@ def upsert( if not connector_type: raise ValueError(f"Expected a non-empty value for `connector_type` but received {connector_type!r}") return self._put( - f"/connector-type-snippets/{connector_type}", + path_template("/connector-type-snippets/{connector_type}", connector_type=connector_type), body=maybe_transform({"usage_snippet": usage_snippet}, type_snippet_upsert_params.TypeSnippetUpsertParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -122,7 +122,7 @@ async def upsert( if not connector_type: raise ValueError(f"Expected a non-empty value for `connector_type` but received {connector_type!r}") return await self._put( - f"/connector-type-snippets/{connector_type}", + path_template("/connector-type-snippets/{connector_type}", connector_type=connector_type), body=await async_maybe_transform( {"usage_snippet": usage_snippet}, type_snippet_upsert_params.TypeSnippetUpsertParams ), diff --git a/src/structify/resources/datasets/datasets.py b/src/structify/resources/datasets/datasets.py index 3e122b78a..952b89283 100644 --- a/src/structify/resources/datasets/datasets.py +++ b/src/structify/resources/datasets/datasets.py @@ -64,6 +64,8 @@ class DatasetsResource(SyncAPIResource): + """Dataset management endpoints""" + @cached_property def evaluate(self) -> EvaluateResource: return EvaluateResource(self._client) @@ -844,6 +846,8 @@ def view_tables_with_relationships( class AsyncDatasetsResource(AsyncAPIResource): + """Dataset management endpoints""" + @cached_property def evaluate(self) -> AsyncEvaluateResource: return AsyncEvaluateResource(self._client) diff --git a/src/structify/resources/jobs.py b/src/structify/resources/jobs.py index 974ece2ed..4caf8e80b 100644 --- a/src/structify/resources/jobs.py +++ b/src/structify/resources/jobs.py @@ -12,7 +12,7 @@ from ..types import job_list_params, job_status_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -23,12 +23,11 @@ ) from ..pagination import SyncJobsList, AsyncJobsList from .._base_client import AsyncPaginator, make_request_options +from ..types.job_get_response import JobGetResponse from ..types.job_list_response import JobListResponse from ..types.job_cancel_response import JobCancelResponse from ..types.job_status_response import JobStatusResponse from ..types.get_job_events_response import GetJobEventsResponse -from ..types.job_get_scrapers_response import JobGetScrapersResponse -from ..types.job_get_source_entities_response import JobGetSourceEntitiesResponse __all__ = ["JobsResource", "AsyncJobsResource"] @@ -57,7 +56,8 @@ def list( self, *, dataset: Optional[str] | Omit = omit, - job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"]] | Omit = omit, + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] + | Omit = omit, limit: int | Omit = omit, node_id: Optional[str] | Omit = omit, offset: int | Omit = omit, @@ -146,14 +146,14 @@ def cancel( if not uuid: raise ValueError(f"Expected a non-empty value for `uuid` but received {uuid!r}") return self._post( - f"/jobs/cancel/{uuid}", + path_template("/jobs/cancel/{uuid}", uuid=uuid), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=JobCancelResponse, ) - def get_events( + def get( self, job_id: str, *, @@ -163,7 +163,7 @@ def get_events( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GetJobEventsResponse: + ) -> JobGetResponse: """ Args: extra_headers: Send extra headers @@ -177,47 +177,14 @@ def get_events( if not job_id: raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return self._get( - f"/jobs/{job_id}/events", + path_template("/jobs/get/{job_id}", job_id=job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GetJobEventsResponse, + cast_to=JobGetResponse, ) - def get_scrapers( - self, - job_id: 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, - ) -> JobGetScrapersResponse: - """ - Retrieve scrapers associated with a job from structify. - - 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 - """ - if not job_id: - raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") - return self._get( - f"/jobs/get_scrapers/{job_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=JobGetScrapersResponse, - ) - - def get_source_entities( + def get_events( self, job_id: str, *, @@ -227,10 +194,8 @@ def get_source_entities( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> JobGetSourceEntitiesResponse: + ) -> GetJobEventsResponse: """ - Get all source entities and their associated sources for a specific job - Args: extra_headers: Send extra headers @@ -243,11 +208,11 @@ def get_source_entities( if not job_id: raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return self._get( - f"/jobs/get_source_entities/{job_id}", + path_template("/jobs/{job_id}/events", job_id=job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=JobGetSourceEntitiesResponse, + cast_to=GetJobEventsResponse, ) def schedule( @@ -410,7 +375,8 @@ def list( self, *, dataset: Optional[str] | Omit = omit, - job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"]] | Omit = omit, + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] + | Omit = omit, limit: int | Omit = omit, node_id: Optional[str] | Omit = omit, offset: int | Omit = omit, @@ -499,45 +465,14 @@ async def cancel( if not uuid: raise ValueError(f"Expected a non-empty value for `uuid` but received {uuid!r}") return await self._post( - f"/jobs/cancel/{uuid}", + path_template("/jobs/cancel/{uuid}", uuid=uuid), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), cast_to=JobCancelResponse, ) - async def get_events( - self, - job_id: 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, - ) -> GetJobEventsResponse: - """ - 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 - """ - if not job_id: - raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") - return await self._get( - f"/jobs/{job_id}/events", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=GetJobEventsResponse, - ) - - async def get_scrapers( + async def get( self, job_id: str, *, @@ -547,10 +482,8 @@ async def get_scrapers( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> JobGetScrapersResponse: + ) -> JobGetResponse: """ - Retrieve scrapers associated with a job from structify. - Args: extra_headers: Send extra headers @@ -563,14 +496,14 @@ async def get_scrapers( if not job_id: raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return await self._get( - f"/jobs/get_scrapers/{job_id}", + path_template("/jobs/get/{job_id}", job_id=job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=JobGetScrapersResponse, + cast_to=JobGetResponse, ) - async def get_source_entities( + async def get_events( self, job_id: str, *, @@ -580,10 +513,8 @@ async def get_source_entities( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> JobGetSourceEntitiesResponse: + ) -> GetJobEventsResponse: """ - Get all source entities and their associated sources for a specific job - Args: extra_headers: Send extra headers @@ -596,11 +527,11 @@ async def get_source_entities( if not job_id: raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return await self._get( - f"/jobs/get_source_entities/{job_id}", + path_template("/jobs/{job_id}/events", job_id=job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=JobGetSourceEntitiesResponse, + cast_to=GetJobEventsResponse, ) async def schedule( @@ -682,15 +613,12 @@ def __init__(self, jobs: JobsResource) -> None: self.cancel = to_raw_response_wrapper( jobs.cancel, ) + self.get = to_raw_response_wrapper( + jobs.get, + ) self.get_events = to_raw_response_wrapper( jobs.get_events, ) - self.get_scrapers = to_raw_response_wrapper( - jobs.get_scrapers, - ) - self.get_source_entities = to_raw_response_wrapper( - jobs.get_source_entities, - ) self.schedule = to_raw_response_wrapper( jobs.schedule, ) @@ -712,15 +640,12 @@ def __init__(self, jobs: AsyncJobsResource) -> None: self.cancel = async_to_raw_response_wrapper( jobs.cancel, ) + self.get = async_to_raw_response_wrapper( + jobs.get, + ) self.get_events = async_to_raw_response_wrapper( jobs.get_events, ) - self.get_scrapers = async_to_raw_response_wrapper( - jobs.get_scrapers, - ) - self.get_source_entities = async_to_raw_response_wrapper( - jobs.get_source_entities, - ) self.schedule = async_to_raw_response_wrapper( jobs.schedule, ) @@ -739,15 +664,12 @@ def __init__(self, jobs: JobsResource) -> None: self.cancel = to_streamed_response_wrapper( jobs.cancel, ) + self.get = to_streamed_response_wrapper( + jobs.get, + ) self.get_events = to_streamed_response_wrapper( jobs.get_events, ) - self.get_scrapers = to_streamed_response_wrapper( - jobs.get_scrapers, - ) - self.get_source_entities = to_streamed_response_wrapper( - jobs.get_source_entities, - ) self.schedule = to_streamed_response_wrapper( jobs.schedule, ) @@ -769,15 +691,12 @@ def __init__(self, jobs: AsyncJobsResource) -> None: self.cancel = async_to_streamed_response_wrapper( jobs.cancel, ) + self.get = async_to_streamed_response_wrapper( + jobs.get, + ) self.get_events = async_to_streamed_response_wrapper( jobs.get_events, ) - self.get_scrapers = async_to_streamed_response_wrapper( - jobs.get_scrapers, - ) - self.get_source_entities = async_to_streamed_response_wrapper( - jobs.get_source_entities, - ) self.schedule = async_to_streamed_response_wrapper( jobs.schedule, ) diff --git a/src/structify/resources/polars.py b/src/structify/resources/polars.py index 6ae6d9d38..3b6dd3c58 100644 --- a/src/structify/resources/polars.py +++ b/src/structify/resources/polars.py @@ -8,10 +8,12 @@ from typing import Any, Dict, List, Tuple, Literal, Optional, cast from concurrent.futures import Future, ThreadPoolExecutor, as_completed +import pypdf import polars as pl from tqdm import tqdm # type: ignore from polars import LazyFrame +from structify import Structify from structify.types.entity_param import EntityParam from structify.types.property_type_param import PropertyTypeParam from structify.types.dataset_create_params import Relationship as CreateRelationshipParam @@ -36,12 +38,13 @@ STRUCTIFY_JOB_ID_COLUMN = "structify_job_id" -def _collect_entities_with_job_ids(entities: Any) -> List[Dict[str, Any]]: - """Collect entity properties with their first job_id.""" +def _collect_entities_with_job_ids(client: Structify, dataset_name: str, table_name: str) -> List[Dict[str, Any]]: + """Collect entity properties with their job_id.""" + entities = client.datasets.view_table(dataset=dataset_name, name=table_name) results: List[Dict[str, Any]] = [] for entity in entities: row: Dict[str, Any] = dict(entity.properties) - row[STRUCTIFY_JOB_ID_COLUMN] = entity.job_ids[0] if entity.job_ids else None + row[STRUCTIFY_JOB_ID_COLUMN] = entity.job_id results.append(row) return results @@ -239,14 +242,10 @@ def enhance_entity_property( else: property_names = f"{', '.join(property_list[:-1])}, and {property_list[-1]}" with ThreadPoolExecutor(max_workers=MAX_PARALLEL_REQUESTS) as executor: - futures: List[Future[None]] = [] - # Iterate through property name at the outer level for queueing so with large requests - # we can skip later jobs if the earlier ones get extra properties. - for property_name in property_list: - futures += [ - executor.submit(enhance_entity_property, entity_id, entity_param, [property_name]) - for entity_id, entity_param in entity_id_to_entity.items() - ] + futures: List[Future[None]] = [ + executor.submit(enhance_entity_property, entity_id, entity_param, property_list) + for entity_id, entity_param in entity_id_to_entity.items() + ] for future in tqdm( as_completed(futures), total=len(futures), desc=f"Preparing enrichments for {property_names}" ): @@ -255,9 +254,7 @@ def enhance_entity_property( title = f"Enriching {property_names} for {dataframe_name}" self._client.jobs.wait_for_jobs(dataset_name=dataset_name, title=title, node_id=node_id) # 4. Collect the results with job_ids - results = _collect_entities_with_job_ids( - self._client.datasets.view_table(dataset=dataset_name, name=dataframe_name) - ) + results = _collect_entities_with_job_ids(self._client, dataset_name, dataframe_name) # 5. Return the results return pl.DataFrame(results, schema=expected_schema) @@ -417,7 +414,7 @@ def enhance_relationship(entity_id: str) -> None: prop_name if prop_name not in input_schema else f"{prop_name}_{target_table_name}" ) # If the column already exists in the input schema, we need to suffix it with the target table name result_row[eff] = target_entity.properties.get(prop_name) - result_row[STRUCTIFY_JOB_ID_COLUMN] = target_entity.job_ids[0] if target_entity.job_ids else None + result_row[STRUCTIFY_JOB_ID_COLUMN] = target_entity.job_id result_rows.append(result_row) # Handle source rows without relationships @@ -590,9 +587,7 @@ def scrape_entity_property(entity_id: str) -> None: self._client.jobs.wait_for_jobs(dataset_name=dataset_name, title=title, node_id=node_id) # 4. Collect the results with job_id - results = _collect_entities_with_job_ids( - self._client.datasets.view_table(dataset=dataset_name, name=dataframe_name) - ) + results = _collect_entities_with_job_ids(self._client, dataset_name, dataframe_name) # 5. Return the results return pl.DataFrame(results, schema=expected_schema) @@ -749,9 +744,7 @@ def scrape_entity(entity: Dict[str, Any]) -> None: result_row: dict[str, Any] = { **scraped_entity.properties, url_column: related_entity.properties[url_column], - STRUCTIFY_JOB_ID_COLUMN: scraped_entity.job_ids[0] - if scraped_entity.job_ids - else None, + STRUCTIFY_JOB_ID_COLUMN: scraped_entity.job_id, } result_rows.append(result_row) offset += LIMIT @@ -845,6 +838,24 @@ def structure_pdfs( table_param = as_table_param(table_name, schema) + paths_df = document_paths.collect() + + page_count_map: dict[str, int] = {} + if mode == "all_pages": + for pdf_path in paths_df[path_column].to_list(): + if pdf_path is not None: + with open(pdf_path, "rb") as f: + pdf = pypdf.PdfReader(f) + page_count_map[pdf_path] = len(pdf.pages) + else: + for pdf_path in paths_df[path_column].to_list(): + # TODO: this is a hack to note that we cost twice as much for single page mode + page_count_map[pdf_path] = 2 + + total_pages = sum(page_count_map.values()) + if not request_cost_confirmation_if_needed(self._client, total_pages, "pdf"): + raise Exception(f"User cancelled PDF extraction for {table_name}") + # Create dataset for this PDF dataset_name = f"structure_pdfs_{table_name}_{uuid.uuid4().hex}" self._client.datasets.create( @@ -865,7 +876,6 @@ def structure_pdfs( "model must be in format 'provider.model_name' (e.g. 'bedrock.claude-sonnet-4-bedrock')" ) - paths_df = document_paths.collect() instructions_list: list[str | None] = [] if instructions is not None and not isinstance(instructions, str): @@ -874,42 +884,50 @@ def structure_pdfs( raise ValueError(f"instructions shape {instr_df.shape} != document_paths shape {paths_df.shape}") instructions_list = cast(List[Optional[str]], instr_df[instr_df.columns[0]].to_list()) - # Request cost confirmation before dispatching costly PDF extraction jobs - if not request_cost_confirmation_if_needed(self._client, paths_df.shape[0], "pdf"): - raise Exception(f"User cancelled PDF extraction for {table_name}") - job_to_pdf_path: dict[str, str] = {} # Process each PDF document - def process_pdf(pdf_path: str, instructions: str | None) -> Tuple[List[str], str]: + def upload_pdf(pdf_path: str) -> None: # Upload the PDF document - unique_pdf_name = f"{uuid.uuid4().hex}.pdf" with open(pdf_path, "rb") as pdf_file: try: self._client.documents.upload( content=pdf_file, file_type="PDF", dataset=dataset_name, - path=unique_pdf_name.encode(), + path=pdf_path.encode(), ) except Exception as e: if "Document already exists" not in str(e): raise e + with ThreadPoolExecutor(max_workers=MAX_PARALLEL_REQUESTS) as executor: + upload_futures: List[Future[None]] = [] + for pdf_path in paths_df[path_column].to_list(): + if isinstance(pdf_path, str): + upload_futures.append(executor.submit(upload_pdf, pdf_path)) + for future in tqdm(as_completed(upload_futures), total=len(upload_futures), desc="Uploading PDFs"): + future.result() + + def structure_pdf(pdf_path: str, instructions: str | None) -> Tuple[List[str], str]: + pages: List[int] | None = None + if mode == "all_pages": + pages = list(range(page_count_map[pdf_path])) + job_ids = self._client.structure.pdf( dataset=dataset_name, - path=unique_pdf_name, + path=pdf_path, node_id=node_id, instructions=instructions, - mode="Single" if mode == "single" else "Batch", model=model, + pages=pages, ).job_ids return job_ids, pdf_path with ThreadPoolExecutor(max_workers=MAX_PARALLEL_REQUESTS) as executor: futures: List[Future[Tuple[List[str], str]]] = [] for i in range(paths_df.shape[0]): - path: str | None = paths_df[path_column][i] + path = paths_df[path_column][i] pdf_instructions: str | None = None if isinstance(instructions, str): pdf_instructions = instructions @@ -917,21 +935,21 @@ def process_pdf(pdf_path: str, instructions: str | None) -> Tuple[List[str], str pdf_instructions = instructions_list[i] if pdf_instructions is None and conditioning: pdf_instructions = conditioning - if path is not None: - futures.append(executor.submit(process_pdf, path, pdf_instructions)) - for future in tqdm(as_completed(futures), total=len(futures), desc="Preparing PDFs"): + if isinstance(path, str): + futures.append(executor.submit(structure_pdf, path, pdf_instructions)) + for future in tqdm(as_completed(futures), total=len(futures), desc="Submitting PDFs for parsing"): job_ids, pdf_path = future.result() for job_id in job_ids: job_to_pdf_path[job_id] = pdf_path # Wait for all PDF processing jobs to complete - self._client.jobs.wait_for_jobs(dataset_name=dataset_name, title=f"Parsing PDFs", node_id=node_id) + self._client.jobs.wait_for_jobs(dataset_name=dataset_name, title=f"Parsing PDF pages", node_id=node_id) # Get all of the entities with their job_ids entities = self._client.datasets.view_table(dataset=dataset_name, name=table_name) structured_results: List[Dict[str, Any]] = [] for entity in entities: - job_id = entity.job_ids[0] if entity.job_ids else None + job_id = entity.job_id result_row: Dict[str, Any] = { **entity.properties, path_column: job_to_pdf_path.get(job_id) if job_id else None, @@ -1032,9 +1050,7 @@ def tag( # 3. Collect the results with job_ids title = f"Tagging {new_property_name} for {dataframe_name}" self._client.jobs.wait_for_jobs(dataset_name=dataset_name, title=title, node_id=node_id) - results = _collect_entities_with_job_ids( - self._client.datasets.view_table(dataset=dataset_name, name=dataframe_name) - ) + results = _collect_entities_with_job_ids(self._client, dataset_name, dataframe_name) # 4. Return the results return pl.DataFrame(results, schema=expected_schema).lazy() diff --git a/src/structify/resources/projects.py b/src/structify/resources/projects.py index 658eadbd2..98eb1c2b5 100644 --- a/src/structify/resources/projects.py +++ b/src/structify/resources/projects.py @@ -8,7 +8,7 @@ from ..types import ProjectVisibility, project_update_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -28,6 +28,8 @@ class ProjectsResource(SyncAPIResource): + """Project management endpoints""" + @cached_property def with_raw_response(self) -> ProjectsResourceWithRawResponse: """ @@ -78,7 +80,7 @@ def update( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._patch( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), body=maybe_transform( { "collaborators": collaborators, @@ -121,7 +123,7 @@ def delete( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._delete( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -155,7 +157,7 @@ def get( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -164,6 +166,8 @@ def get( class AsyncProjectsResource(AsyncAPIResource): + """Project management endpoints""" + @cached_property def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: """ @@ -214,7 +218,7 @@ async def update( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._patch( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), body=await async_maybe_transform( { "collaborators": collaborators, @@ -257,7 +261,7 @@ async def delete( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._delete( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -291,7 +295,7 @@ async def get( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._get( - f"/team/{team_id}/project/{project_id}", + path_template("/team/{team_id}/project/{project_id}", team_id=team_id, project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/public_sessions.py b/src/structify/resources/public_sessions.py index 65bc52ffc..eb8136ff7 100644 --- a/src/structify/resources/public_sessions.py +++ b/src/structify/resources/public_sessions.py @@ -5,6 +5,7 @@ import httpx from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -71,7 +72,7 @@ def get_latest_workflow( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return self._get( - f"/public/chat/{chat_session_id}/latest-workflow", + path_template("/public/chat/{chat_session_id}/latest-workflow", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -103,7 +104,7 @@ def get_node_output_data( raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return self._get( - f"/public/nodes/{node_id}/output_data", + path_template("/public/nodes/{node_id}/output_data", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -155,7 +156,7 @@ async def get_latest_workflow( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return await self._get( - f"/public/chat/{chat_session_id}/latest-workflow", + path_template("/public/chat/{chat_session_id}/latest-workflow", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -187,7 +188,7 @@ async def get_node_output_data( raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return await self._get( - f"/public/nodes/{node_id}/output_data", + path_template("/public/nodes/{node_id}/output_data", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/sandbox.py b/src/structify/resources/sandbox.py index 7f9c9bdfc..1a47e4931 100644 --- a/src/structify/resources/sandbox.py +++ b/src/structify/resources/sandbox.py @@ -8,7 +8,7 @@ from ..types import sandbox_get_params, sandbox_update_status_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -20,11 +20,14 @@ from .._base_client import make_request_options from ..types.sandbox import Sandbox from ..types.sandbox_list_response import SandboxListResponse +from ..types.sandbox_get_metrics_response import SandboxGetMetricsResponse __all__ = ["SandboxResource", "AsyncSandboxResource"] class SandboxResource(SyncAPIResource): + """Sandbox management endpoints""" + @cached_property def with_raw_response(self) -> SandboxResourceWithRawResponse: """ @@ -68,7 +71,7 @@ def list( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return self._get( - f"/sandbox/list/{chat_id}", + path_template("/sandbox/list/{chat_id}", chat_id=chat_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -102,7 +105,7 @@ def get( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return self._post( - f"/sandbox/live/{chat_id}", + path_template("/sandbox/live/{chat_id}", chat_id=chat_id), body=maybe_transform( {"modal_control_service_url_override": modal_control_service_url_override}, sandbox_get_params.SandboxGetParams, @@ -113,6 +116,37 @@ def get( cast_to=Sandbox, ) + def get_metrics( + self, + sandbox_id: 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, + ) -> SandboxGetMetricsResponse: + """ + 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 + """ + if not sandbox_id: + raise ValueError(f"Expected a non-empty value for `sandbox_id` but received {sandbox_id!r}") + return self._get( + path_template("/sandbox/{sandbox_id}/metrics", sandbox_id=sandbox_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SandboxGetMetricsResponse, + ) + def update_status( self, sandbox_id: str, @@ -138,7 +172,7 @@ def update_status( if not sandbox_id: raise ValueError(f"Expected a non-empty value for `sandbox_id` but received {sandbox_id!r}") return self._patch( - f"/sandbox/{sandbox_id}/status", + path_template("/sandbox/{sandbox_id}/status", sandbox_id=sandbox_id), body=maybe_transform({"status": status}, sandbox_update_status_params.SandboxUpdateStatusParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -148,6 +182,8 @@ def update_status( class AsyncSandboxResource(AsyncAPIResource): + """Sandbox management endpoints""" + @cached_property def with_raw_response(self) -> AsyncSandboxResourceWithRawResponse: """ @@ -191,7 +227,7 @@ async def list( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return await self._get( - f"/sandbox/list/{chat_id}", + path_template("/sandbox/list/{chat_id}", chat_id=chat_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -225,7 +261,7 @@ async def get( if not chat_id: raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") return await self._post( - f"/sandbox/live/{chat_id}", + path_template("/sandbox/live/{chat_id}", chat_id=chat_id), body=await async_maybe_transform( {"modal_control_service_url_override": modal_control_service_url_override}, sandbox_get_params.SandboxGetParams, @@ -236,6 +272,37 @@ async def get( cast_to=Sandbox, ) + async def get_metrics( + self, + sandbox_id: 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, + ) -> SandboxGetMetricsResponse: + """ + 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 + """ + if not sandbox_id: + raise ValueError(f"Expected a non-empty value for `sandbox_id` but received {sandbox_id!r}") + return await self._get( + path_template("/sandbox/{sandbox_id}/metrics", sandbox_id=sandbox_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SandboxGetMetricsResponse, + ) + async def update_status( self, sandbox_id: str, @@ -261,7 +328,7 @@ async def update_status( if not sandbox_id: raise ValueError(f"Expected a non-empty value for `sandbox_id` but received {sandbox_id!r}") return await self._patch( - f"/sandbox/{sandbox_id}/status", + path_template("/sandbox/{sandbox_id}/status", sandbox_id=sandbox_id), body=await async_maybe_transform( {"status": status}, sandbox_update_status_params.SandboxUpdateStatusParams ), @@ -282,6 +349,9 @@ def __init__(self, sandbox: SandboxResource) -> None: self.get = to_raw_response_wrapper( sandbox.get, ) + self.get_metrics = to_raw_response_wrapper( + sandbox.get_metrics, + ) self.update_status = to_raw_response_wrapper( sandbox.update_status, ) @@ -297,6 +367,9 @@ def __init__(self, sandbox: AsyncSandboxResource) -> None: self.get = async_to_raw_response_wrapper( sandbox.get, ) + self.get_metrics = async_to_raw_response_wrapper( + sandbox.get_metrics, + ) self.update_status = async_to_raw_response_wrapper( sandbox.update_status, ) @@ -312,6 +385,9 @@ def __init__(self, sandbox: SandboxResource) -> None: self.get = to_streamed_response_wrapper( sandbox.get, ) + self.get_metrics = to_streamed_response_wrapper( + sandbox.get_metrics, + ) self.update_status = to_streamed_response_wrapper( sandbox.update_status, ) @@ -327,6 +403,9 @@ def __init__(self, sandbox: AsyncSandboxResource) -> None: self.get = async_to_streamed_response_wrapper( sandbox.get, ) + self.get_metrics = async_to_streamed_response_wrapper( + sandbox.get_metrics, + ) self.update_status = async_to_streamed_response_wrapper( sandbox.update_status, ) diff --git a/src/structify/resources/sessions.py b/src/structify/resources/sessions.py index 658ce3c43..08f675436 100644 --- a/src/structify/resources/sessions.py +++ b/src/structify/resources/sessions.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Dict, Mapping, Iterable, Optional, cast -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx @@ -25,7 +25,14 @@ session_upload_node_visualization_output_params, ) from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import ( + extract_files, + path_template, + required_args, + maybe_transform, + deepcopy_minimal, + async_maybe_transform, +) from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -54,6 +61,7 @@ from ..types.finalize_dag_response import FinalizeDagResponse from ..types.workflow_session_node import WorkflowSessionNode from ..types.get_node_logs_response import GetNodeLogsResponse +from ..types.trigger_review_response import TriggerReviewResponse from ..types.session_kill_jobs_response import SessionKillJobsResponse from ..types.session_get_events_response import SessionGetEventsResponse from ..types.workflow_node_execution_status import WorkflowNodeExecutionStatus @@ -108,7 +116,7 @@ def confirm_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._post( - f"/sessions/nodes/{node_id}/confirm", + path_template("/sessions/nodes/{node_id}/confirm", node_id=node_id), body=maybe_transform({"confirmed": confirmed}, session_confirm_node_params.SessionConfirmNodeParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -120,7 +128,7 @@ def create_session( self, *, chat_session_id: str, - git_commit: str, + parent_chat_message_id: Optional[str] | Omit = omit, workflow_schedule_id: Optional[str] | Omit = omit, # 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. @@ -144,7 +152,7 @@ def create_session( body=maybe_transform( { "chat_session_id": chat_session_id, - "git_commit": git_commit, + "parent_chat_message_id": parent_chat_message_id, "workflow_schedule_id": workflow_schedule_id, }, session_create_session_params.SessionCreateSessionParams, @@ -180,7 +188,7 @@ def edit_node_output( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._post( - f"/sessions/nodes/{node_id}/edit_output", + path_template("/sessions/nodes/{node_id}/edit_output", node_id=node_id), body=maybe_transform({"edits": edits}, session_edit_node_output_params.SessionEditNodeOutputParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -221,7 +229,7 @@ def finalize_dag( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/sessions/{session_id}/dag_ready", + path_template("/sessions/{session_id}/dag_ready", session_id=session_id), body=maybe_transform( { "edges": edges, @@ -260,7 +268,7 @@ def get_dag( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._get( - f"/sessions/{session_id}/dag", + path_template("/sessions/{session_id}/dag", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -297,7 +305,7 @@ def get_events( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._get( - f"/sessions/nodes/{node_id}/events", + path_template("/sessions/nodes/{node_id}/events", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -340,7 +348,7 @@ def get_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._get( - f"/sessions/nodes/{node_id}", + path_template("/sessions/nodes/{node_id}", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -373,7 +381,7 @@ def get_node_logs( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._get( - f"/sessions/node/{node_id}/logs", + path_template("/sessions/node/{node_id}/logs", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -405,7 +413,7 @@ def get_node_output_data( raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return self._get( - f"/sessions/nodes/{node_id}/output_data", + path_template("/sessions/nodes/{node_id}/output_data", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -436,7 +444,7 @@ def get_node_progress( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._get( - f"/sessions/nodes/{node_id}/progress", + path_template("/sessions/nodes/{node_id}/progress", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -468,7 +476,7 @@ def kill_jobs( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/sessions/{session_id}/kill_jobs", + path_template("/sessions/{session_id}/kill_jobs", session_id=session_id), body=maybe_transform({"message": message}, session_kill_jobs_params.SessionKillJobsParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -504,7 +512,7 @@ def mark_errored( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._patch( - f"/sessions/{session_id}/error", + path_template("/sessions/{session_id}/error", session_id=session_id), body=maybe_transform( { "error_message": error_message, @@ -546,7 +554,7 @@ def request_confirmation( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._post( - f"/sessions/nodes/{node_id}/request_confirmation", + path_template("/sessions/nodes/{node_id}/request_confirmation", node_id=node_id), body=maybe_transform( { "operation": operation, @@ -560,6 +568,37 @@ def request_confirmation( cast_to=WorkflowSessionNode, ) + def trigger_review( + self, + session_id: 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, + ) -> TriggerReviewResponse: + """ + 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 + """ + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + return self._post( + path_template("/sessions/{session_id}/trigger_review", session_id=session_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TriggerReviewResponse, + ) + def update_node( self, node_id: str, @@ -588,7 +627,7 @@ def update_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._patch( - f"/sessions/nodes/{node_id}", + path_template("/sessions/nodes/{node_id}", node_id=node_id), body=maybe_transform( { "execution_status": execution_status, @@ -632,7 +671,7 @@ def update_node_progress( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._patch( - f"/sessions/nodes/{node_id}/progress", + path_template("/sessions/nodes/{node_id}/progress", node_id=node_id), body=maybe_transform( { "current": current, @@ -648,6 +687,7 @@ def update_node_progress( cast_to=WorkflowSessionNode, ) + @overload def upload_dashboard_layout( self, session_id: str, @@ -673,12 +713,57 @@ def upload_dashboard_layout( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @overload + def upload_dashboard_layout( + self, + session_id: str, + *, + dashboard_specs: Iterable[session_upload_dashboard_layout_params.Variant1DashboardSpec], + # 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, + ) -> WorkflowSession: + """ + 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 + """ + ... + + @required_args(["layout"], ["dashboard_specs"]) + def upload_dashboard_layout( + self, + session_id: str, + *, + layout: DashboardParam | Omit = omit, + dashboard_specs: Iterable[session_upload_dashboard_layout_params.Variant1DashboardSpec] | Omit = omit, + # 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, + ) -> WorkflowSession: if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return self._post( - f"/sessions/{session_id}/dashboard_layout", + path_template("/sessions/{session_id}/dashboard_layout", session_id=session_id), body=maybe_transform( - {"layout": layout}, session_upload_dashboard_layout_params.SessionUploadDashboardLayoutParams + { + "layout": layout, + "dashboard_specs": dashboard_specs, + }, + session_upload_dashboard_layout_params.SessionUploadDashboardLayoutParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -691,6 +776,12 @@ def upload_node_output_data( node_id: str, *, content: FileTypes, + cache_final_rows: Optional[int] | Omit = omit, + cache_final_size_bytes: Optional[int] | Omit = omit, + cache_max_bytes: Optional[int] | Omit = omit, + cache_original_rows: Optional[int] | Omit = omit, + cache_original_size_bytes: Optional[int] | Omit = omit, + cache_truncated: Optional[bool] | Omit = omit, output_schema: Optional[str] | Omit = omit, # 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. @@ -714,6 +805,12 @@ def upload_node_output_data( body = deepcopy_minimal( { "content": content, + "cache_final_rows": cache_final_rows, + "cache_final_size_bytes": cache_final_size_bytes, + "cache_max_bytes": cache_max_bytes, + "cache_original_rows": cache_original_rows, + "cache_original_size_bytes": cache_original_size_bytes, + "cache_truncated": cache_truncated, "output_schema": output_schema, } ) @@ -723,7 +820,7 @@ def upload_node_output_data( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/sessions/nodes/{node_id}/output_data", + path_template("/sessions/nodes/{node_id}/output_data", node_id=node_id), body=maybe_transform(body, session_upload_node_output_data_params.SessionUploadNodeOutputDataParams), files=files, options=make_request_options( @@ -757,7 +854,7 @@ def upload_node_visualization_output( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return self._post( - f"/sessions/nodes/{node_id}/visualization_output", + path_template("/sessions/nodes/{node_id}/visualization_output", node_id=node_id), body=maybe_transform( {"visualization_output": visualization_output}, session_upload_node_visualization_output_params.SessionUploadNodeVisualizationOutputParams, @@ -814,7 +911,7 @@ async def confirm_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._post( - f"/sessions/nodes/{node_id}/confirm", + path_template("/sessions/nodes/{node_id}/confirm", node_id=node_id), body=await async_maybe_transform( {"confirmed": confirmed}, session_confirm_node_params.SessionConfirmNodeParams ), @@ -828,7 +925,7 @@ async def create_session( self, *, chat_session_id: str, - git_commit: str, + parent_chat_message_id: Optional[str] | Omit = omit, workflow_schedule_id: Optional[str] | Omit = omit, # 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. @@ -852,7 +949,7 @@ async def create_session( body=await async_maybe_transform( { "chat_session_id": chat_session_id, - "git_commit": git_commit, + "parent_chat_message_id": parent_chat_message_id, "workflow_schedule_id": workflow_schedule_id, }, session_create_session_params.SessionCreateSessionParams, @@ -888,7 +985,7 @@ async def edit_node_output( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._post( - f"/sessions/nodes/{node_id}/edit_output", + path_template("/sessions/nodes/{node_id}/edit_output", node_id=node_id), body=await async_maybe_transform( {"edits": edits}, session_edit_node_output_params.SessionEditNodeOutputParams ), @@ -931,7 +1028,7 @@ async def finalize_dag( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/sessions/{session_id}/dag_ready", + path_template("/sessions/{session_id}/dag_ready", session_id=session_id), body=await async_maybe_transform( { "edges": edges, @@ -970,7 +1067,7 @@ async def get_dag( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._get( - f"/sessions/{session_id}/dag", + path_template("/sessions/{session_id}/dag", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1007,7 +1104,7 @@ async def get_events( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._get( - f"/sessions/nodes/{node_id}/events", + path_template("/sessions/nodes/{node_id}/events", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1050,7 +1147,7 @@ async def get_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._get( - f"/sessions/nodes/{node_id}", + path_template("/sessions/nodes/{node_id}", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1083,7 +1180,7 @@ async def get_node_logs( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._get( - f"/sessions/node/{node_id}/logs", + path_template("/sessions/node/{node_id}/logs", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1115,7 +1212,7 @@ async def get_node_output_data( raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})} return await self._get( - f"/sessions/nodes/{node_id}/output_data", + path_template("/sessions/nodes/{node_id}/output_data", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1146,7 +1243,7 @@ async def get_node_progress( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._get( - f"/sessions/nodes/{node_id}/progress", + path_template("/sessions/nodes/{node_id}/progress", node_id=node_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1178,7 +1275,7 @@ async def kill_jobs( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/sessions/{session_id}/kill_jobs", + path_template("/sessions/{session_id}/kill_jobs", session_id=session_id), body=await async_maybe_transform({"message": message}, session_kill_jobs_params.SessionKillJobsParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1214,7 +1311,7 @@ async def mark_errored( if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._patch( - f"/sessions/{session_id}/error", + path_template("/sessions/{session_id}/error", session_id=session_id), body=await async_maybe_transform( { "error_message": error_message, @@ -1256,7 +1353,7 @@ async def request_confirmation( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._post( - f"/sessions/nodes/{node_id}/request_confirmation", + path_template("/sessions/nodes/{node_id}/request_confirmation", node_id=node_id), body=await async_maybe_transform( { "operation": operation, @@ -1270,6 +1367,37 @@ async def request_confirmation( cast_to=WorkflowSessionNode, ) + async def trigger_review( + self, + session_id: 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, + ) -> TriggerReviewResponse: + """ + 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 + """ + if not session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + return await self._post( + path_template("/sessions/{session_id}/trigger_review", session_id=session_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TriggerReviewResponse, + ) + async def update_node( self, node_id: str, @@ -1298,7 +1426,7 @@ async def update_node( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._patch( - f"/sessions/nodes/{node_id}", + path_template("/sessions/nodes/{node_id}", node_id=node_id), body=await async_maybe_transform( { "execution_status": execution_status, @@ -1342,7 +1470,7 @@ async def update_node_progress( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._patch( - f"/sessions/nodes/{node_id}/progress", + path_template("/sessions/nodes/{node_id}/progress", node_id=node_id), body=await async_maybe_transform( { "current": current, @@ -1358,6 +1486,7 @@ async def update_node_progress( cast_to=WorkflowSessionNode, ) + @overload async def upload_dashboard_layout( self, session_id: str, @@ -1383,12 +1512,57 @@ async def upload_dashboard_layout( timeout: Override the client-level default timeout for this request, in seconds """ + ... + + @overload + async def upload_dashboard_layout( + self, + session_id: str, + *, + dashboard_specs: Iterable[session_upload_dashboard_layout_params.Variant1DashboardSpec], + # 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, + ) -> WorkflowSession: + """ + 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 + """ + ... + + @required_args(["layout"], ["dashboard_specs"]) + async def upload_dashboard_layout( + self, + session_id: str, + *, + layout: DashboardParam | Omit = omit, + dashboard_specs: Iterable[session_upload_dashboard_layout_params.Variant1DashboardSpec] | Omit = omit, + # 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, + ) -> WorkflowSession: if not session_id: raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") return await self._post( - f"/sessions/{session_id}/dashboard_layout", + path_template("/sessions/{session_id}/dashboard_layout", session_id=session_id), body=await async_maybe_transform( - {"layout": layout}, session_upload_dashboard_layout_params.SessionUploadDashboardLayoutParams + { + "layout": layout, + "dashboard_specs": dashboard_specs, + }, + session_upload_dashboard_layout_params.SessionUploadDashboardLayoutParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1401,6 +1575,12 @@ async def upload_node_output_data( node_id: str, *, content: FileTypes, + cache_final_rows: Optional[int] | Omit = omit, + cache_final_size_bytes: Optional[int] | Omit = omit, + cache_max_bytes: Optional[int] | Omit = omit, + cache_original_rows: Optional[int] | Omit = omit, + cache_original_size_bytes: Optional[int] | Omit = omit, + cache_truncated: Optional[bool] | Omit = omit, output_schema: Optional[str] | Omit = omit, # 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. @@ -1424,6 +1604,12 @@ async def upload_node_output_data( body = deepcopy_minimal( { "content": content, + "cache_final_rows": cache_final_rows, + "cache_final_size_bytes": cache_final_size_bytes, + "cache_max_bytes": cache_max_bytes, + "cache_original_rows": cache_original_rows, + "cache_original_size_bytes": cache_original_size_bytes, + "cache_truncated": cache_truncated, "output_schema": output_schema, } ) @@ -1433,7 +1619,7 @@ async def upload_node_output_data( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/sessions/nodes/{node_id}/output_data", + path_template("/sessions/nodes/{node_id}/output_data", node_id=node_id), body=await async_maybe_transform( body, session_upload_node_output_data_params.SessionUploadNodeOutputDataParams ), @@ -1469,7 +1655,7 @@ async def upload_node_visualization_output( if not node_id: raise ValueError(f"Expected a non-empty value for `node_id` but received {node_id!r}") return await self._post( - f"/sessions/nodes/{node_id}/visualization_output", + path_template("/sessions/nodes/{node_id}/visualization_output", node_id=node_id), body=await async_maybe_transform( {"visualization_output": visualization_output}, session_upload_node_visualization_output_params.SessionUploadNodeVisualizationOutputParams, @@ -1525,6 +1711,9 @@ def __init__(self, sessions: SessionsResource) -> None: self.request_confirmation = to_raw_response_wrapper( sessions.request_confirmation, ) + self.trigger_review = to_raw_response_wrapper( + sessions.trigger_review, + ) self.update_node = to_raw_response_wrapper( sessions.update_node, ) @@ -1586,6 +1775,9 @@ def __init__(self, sessions: AsyncSessionsResource) -> None: self.request_confirmation = async_to_raw_response_wrapper( sessions.request_confirmation, ) + self.trigger_review = async_to_raw_response_wrapper( + sessions.trigger_review, + ) self.update_node = async_to_raw_response_wrapper( sessions.update_node, ) @@ -1647,6 +1839,9 @@ def __init__(self, sessions: SessionsResource) -> None: self.request_confirmation = to_streamed_response_wrapper( sessions.request_confirmation, ) + self.trigger_review = to_streamed_response_wrapper( + sessions.trigger_review, + ) self.update_node = to_streamed_response_wrapper( sessions.update_node, ) @@ -1708,6 +1903,9 @@ def __init__(self, sessions: AsyncSessionsResource) -> None: self.request_confirmation = async_to_streamed_response_wrapper( sessions.request_confirmation, ) + self.trigger_review = async_to_streamed_response_wrapper( + sessions.trigger_review, + ) self.update_node = async_to_streamed_response_wrapper( sessions.update_node, ) diff --git a/src/structify/resources/structure.py b/src/structify/resources/structure.py index 2581b5794..e004296d8 100644 --- a/src/structify/resources/structure.py +++ b/src/structify/resources/structure.py @@ -3,7 +3,6 @@ from __future__ import annotations from typing import Iterable, Optional -from typing_extensions import Literal import httpx @@ -276,9 +275,9 @@ def pdf( dataset: str, path: str, instructions: Optional[str] | Omit = omit, - mode: Literal["Single", "Batch"] | Omit = omit, model: Optional[str] | Omit = omit, node_id: Optional[str] | Omit = omit, + pages: Optional[Iterable[int]] | Omit = omit, # 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, @@ -307,9 +306,9 @@ def pdf( "dataset": dataset, "path": path, "instructions": instructions, - "mode": mode, "model": model, "node_id": node_id, + "pages": pages, }, structure_pdf_params.StructurePdfParams, ), @@ -616,9 +615,9 @@ async def pdf( dataset: str, path: str, instructions: Optional[str] | Omit = omit, - mode: Literal["Single", "Batch"] | Omit = omit, model: Optional[str] | Omit = omit, node_id: Optional[str] | Omit = omit, + pages: Optional[Iterable[int]] | Omit = omit, # 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, @@ -647,9 +646,9 @@ async def pdf( "dataset": dataset, "path": path, "instructions": instructions, - "mode": mode, "model": model, "node_id": node_id, + "pages": pages, }, structure_pdf_params.StructurePdfParams, ), diff --git a/src/structify/resources/teams.py b/src/structify/resources/teams.py index 6513fc06f..45134d829 100644 --- a/src/structify/resources/teams.py +++ b/src/structify/resources/teams.py @@ -4,6 +4,7 @@ from typing import Union, Optional from datetime import datetime +from typing_extensions import Literal import httpx @@ -20,7 +21,7 @@ team_update_member_role_params, ) from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -111,9 +112,10 @@ def update( self, team_id: str, *, + daytona_credentials: Optional[team_update_params.DaytonaCredentials] | Omit = omit, description: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, - pipedream_project_id: Optional[str] | Omit = omit, + sandbox_provider: Optional[Literal["modal", "daytona"]] | Omit = omit, slack_bot_token: Optional[str] | Omit = omit, slack_team_icon: Optional[str] | Omit = omit, slack_team_id: Optional[str] | Omit = omit, @@ -121,6 +123,7 @@ def update( teams_app_id: Optional[str] | Omit = omit, teams_app_password: Optional[str] | Omit = omit, teams_tenant_id: Optional[str] | Omit = omit, + workflow_bucket: Optional[team_update_params.WorkflowBucket] | Omit = omit, # 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, @@ -141,12 +144,13 @@ def update( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._put( - f"/team/{team_id}", + path_template("/team/{team_id}", team_id=team_id), body=maybe_transform( { + "daytona_credentials": daytona_credentials, "description": description, "name": name, - "pipedream_project_id": pipedream_project_id, + "sandbox_provider": sandbox_provider, "slack_bot_token": slack_bot_token, "slack_team_icon": slack_team_icon, "slack_team_id": slack_team_id, @@ -154,6 +158,7 @@ def update( "teams_app_id": teams_app_id, "teams_app_password": teams_app_password, "teams_tenant_id": teams_tenant_id, + "workflow_bucket": workflow_bucket, }, team_update_params.TeamUpdateParams, ), @@ -237,7 +242,7 @@ def add_member( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._post( - f"/team/{team_id}/members", + path_template("/team/{team_id}/members", team_id=team_id), body=maybe_transform( { "email": email, @@ -277,7 +282,7 @@ def cancel_invitation( raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/team/{team_id}/invitations", + path_template("/team/{team_id}/invitations", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -314,7 +319,7 @@ def create_project( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._post( - f"/team/{team_id}/projects", + path_template("/team/{team_id}/projects", team_id=team_id), body=maybe_transform( { "name": name, @@ -364,7 +369,7 @@ def credits_usage( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/team/{team_id}/credits/usage", + path_template("/team/{team_id}/credits/usage", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -407,7 +412,7 @@ def get( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/team/{team_id}", + path_template("/team/{team_id}", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -438,7 +443,7 @@ def invitation_details( if not token: raise ValueError(f"Expected a non-empty value for `token` but received {token!r}") return self._get( - f"/team/invitations/details/{token}", + path_template("/team/invitations/details/{token}", token=token), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -469,7 +474,7 @@ def list_members( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/team/{team_id}/members", + path_template("/team/{team_id}/members", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -500,7 +505,7 @@ def list_projects( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/team/{team_id}/projects", + path_template("/team/{team_id}/projects", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -534,7 +539,7 @@ def remove_member( if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._delete( - f"/team/{team_id}/members/{user_id}", + path_template("/team/{team_id}/members/{user_id}", team_id=team_id, user_id=user_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -565,7 +570,7 @@ def select( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._post( - f"/team/{team_id}/select", + path_template("/team/{team_id}/select", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -600,7 +605,7 @@ def update_member_role( if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return self._patch( - f"/team/{team_id}/members/{user_id}/role", + path_template("/team/{team_id}/members/{user_id}/role", team_id=team_id, user_id=user_id), body=maybe_transform({"role": role}, team_update_member_role_params.TeamUpdateMemberRoleParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -670,9 +675,10 @@ async def update( self, team_id: str, *, + daytona_credentials: Optional[team_update_params.DaytonaCredentials] | Omit = omit, description: Optional[str] | Omit = omit, name: Optional[str] | Omit = omit, - pipedream_project_id: Optional[str] | Omit = omit, + sandbox_provider: Optional[Literal["modal", "daytona"]] | Omit = omit, slack_bot_token: Optional[str] | Omit = omit, slack_team_icon: Optional[str] | Omit = omit, slack_team_id: Optional[str] | Omit = omit, @@ -680,6 +686,7 @@ async def update( teams_app_id: Optional[str] | Omit = omit, teams_app_password: Optional[str] | Omit = omit, teams_tenant_id: Optional[str] | Omit = omit, + workflow_bucket: Optional[team_update_params.WorkflowBucket] | Omit = omit, # 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, @@ -700,12 +707,13 @@ async def update( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._put( - f"/team/{team_id}", + path_template("/team/{team_id}", team_id=team_id), body=await async_maybe_transform( { + "daytona_credentials": daytona_credentials, "description": description, "name": name, - "pipedream_project_id": pipedream_project_id, + "sandbox_provider": sandbox_provider, "slack_bot_token": slack_bot_token, "slack_team_icon": slack_team_icon, "slack_team_id": slack_team_id, @@ -713,6 +721,7 @@ async def update( "teams_app_id": teams_app_id, "teams_app_password": teams_app_password, "teams_tenant_id": teams_tenant_id, + "workflow_bucket": workflow_bucket, }, team_update_params.TeamUpdateParams, ), @@ -798,7 +807,7 @@ async def add_member( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._post( - f"/team/{team_id}/members", + path_template("/team/{team_id}/members", team_id=team_id), body=await async_maybe_transform( { "email": email, @@ -838,7 +847,7 @@ async def cancel_invitation( raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/team/{team_id}/invitations", + path_template("/team/{team_id}/invitations", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -877,7 +886,7 @@ async def create_project( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._post( - f"/team/{team_id}/projects", + path_template("/team/{team_id}/projects", team_id=team_id), body=await async_maybe_transform( { "name": name, @@ -927,7 +936,7 @@ async def credits_usage( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/team/{team_id}/credits/usage", + path_template("/team/{team_id}/credits/usage", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -970,7 +979,7 @@ async def get( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/team/{team_id}", + path_template("/team/{team_id}", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1001,7 +1010,7 @@ async def invitation_details( if not token: raise ValueError(f"Expected a non-empty value for `token` but received {token!r}") return await self._get( - f"/team/invitations/details/{token}", + path_template("/team/invitations/details/{token}", token=token), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1032,7 +1041,7 @@ async def list_members( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/team/{team_id}/members", + path_template("/team/{team_id}/members", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1063,7 +1072,7 @@ async def list_projects( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/team/{team_id}/projects", + path_template("/team/{team_id}/projects", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1097,7 +1106,7 @@ async def remove_member( if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return await self._delete( - f"/team/{team_id}/members/{user_id}", + path_template("/team/{team_id}/members/{user_id}", team_id=team_id, user_id=user_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1128,7 +1137,7 @@ async def select( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._post( - f"/team/{team_id}/select", + path_template("/team/{team_id}/select", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1163,7 +1172,7 @@ async def update_member_role( if not user_id: raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}") return await self._patch( - f"/team/{team_id}/members/{user_id}/role", + path_template("/team/{team_id}/members/{user_id}/role", team_id=team_id, user_id=user_id), body=await async_maybe_transform({"role": role}, team_update_member_role_params.TeamUpdateMemberRoleParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/structify/resources/user/api_keys.py b/src/structify/resources/user/api_keys.py index 6cb18071a..1adb80f3f 100644 --- a/src/structify/resources/user/api_keys.py +++ b/src/structify/resources/user/api_keys.py @@ -8,7 +8,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -27,6 +27,8 @@ class APIKeysResource(SyncAPIResource): + """All the accessible information about your account through our API""" + @cached_property def with_raw_response(self) -> APIKeysResourceWithRawResponse: """ @@ -127,7 +129,7 @@ def get( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._get( - f"/user/api_keys/{id}", + path_template("/user/api_keys/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -159,7 +161,7 @@ def revoke( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/user/api_keys/{id}", + path_template("/user/api_keys/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -168,6 +170,8 @@ def revoke( class AsyncAPIKeysResource(AsyncAPIResource): + """All the accessible information about your account through our API""" + @cached_property def with_raw_response(self) -> AsyncAPIKeysResourceWithRawResponse: """ @@ -268,7 +272,7 @@ async def get( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._get( - f"/user/api_keys/{id}", + path_template("/user/api_keys/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -300,7 +304,7 @@ async def revoke( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/user/api_keys/{id}", + path_template("/user/api_keys/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/user/user.py b/src/structify/resources/user/user.py index da9af3724..9d97998a5 100644 --- a/src/structify/resources/user/user.py +++ b/src/structify/resources/user/user.py @@ -20,6 +20,7 @@ user_update_params, user_refresh_params, user_survey_submit_params, + user_save_onboarding_answers_params, ) from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform @@ -43,9 +44,12 @@ from ...types.user_info import UserInfo from ...types.admin.user import User from ...types.user_usage_response import UserUsageResponse +from ...types.onboarding_answers_param import OnboardingAnswersParam from ...types.refresh_session_response import RefreshSessionResponse from ...types.survey_submission_response import SurveySubmissionResponse from ...types.user_transactions_response import UserTransactionsResponse +from ...types.get_onboarding_answers_response import GetOnboardingAnswersResponse +from ...types.save_onboarding_answers_response import SaveOnboardingAnswersResponse __all__ = ["UserResource", "AsyncUserResource"] @@ -57,6 +61,7 @@ def stripe(self) -> StripeResource: @cached_property def api_keys(self) -> APIKeysResource: + """All the accessible information about your account through our API""" return APIKeysResource(self._client) @cached_property @@ -148,6 +153,24 @@ def enrich( cast_to=NoneType, ) + def get_onboarding_answers( + 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, + ) -> GetOnboardingAnswersResponse: + return self._get( + "/user/onboarding/answers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GetOnboardingAnswersResponse, + ) + def info( self, *, @@ -208,6 +231,38 @@ def refresh( cast_to=RefreshSessionResponse, ) + def save_onboarding_answers( + self, + *, + answers: OnboardingAnswersParam, + # 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, + ) -> SaveOnboardingAnswersResponse: + """ + 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._put( + "/user/onboarding/answers", + body=maybe_transform( + {"answers": answers}, user_save_onboarding_answers_params.UserSaveOnboardingAnswersParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SaveOnboardingAnswersResponse, + ) + def survey_submit( self, *, @@ -303,6 +358,7 @@ def stripe(self) -> AsyncStripeResource: @cached_property def api_keys(self) -> AsyncAPIKeysResource: + """All the accessible information about your account through our API""" return AsyncAPIKeysResource(self._client) @cached_property @@ -394,6 +450,24 @@ async def enrich( cast_to=NoneType, ) + async def get_onboarding_answers( + 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, + ) -> GetOnboardingAnswersResponse: + return await self._get( + "/user/onboarding/answers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GetOnboardingAnswersResponse, + ) + async def info( self, *, @@ -454,6 +528,38 @@ async def refresh( cast_to=RefreshSessionResponse, ) + async def save_onboarding_answers( + self, + *, + answers: OnboardingAnswersParam, + # 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, + ) -> SaveOnboardingAnswersResponse: + """ + 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._put( + "/user/onboarding/answers", + body=await async_maybe_transform( + {"answers": answers}, user_save_onboarding_answers_params.UserSaveOnboardingAnswersParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SaveOnboardingAnswersResponse, + ) + async def survey_submit( self, *, @@ -552,12 +658,18 @@ def __init__(self, user: UserResource) -> None: self.enrich = to_raw_response_wrapper( user.enrich, ) + self.get_onboarding_answers = to_raw_response_wrapper( + user.get_onboarding_answers, + ) self.info = to_raw_response_wrapper( user.info, ) self.refresh = to_raw_response_wrapper( user.refresh, ) + self.save_onboarding_answers = to_raw_response_wrapper( + user.save_onboarding_answers, + ) self.survey_submit = to_raw_response_wrapper( user.survey_submit, ) @@ -574,6 +686,7 @@ def stripe(self) -> StripeResourceWithRawResponse: @cached_property def api_keys(self) -> APIKeysResourceWithRawResponse: + """All the accessible information about your account through our API""" return APIKeysResourceWithRawResponse(self._user.api_keys) @@ -587,12 +700,18 @@ def __init__(self, user: AsyncUserResource) -> None: self.enrich = async_to_raw_response_wrapper( user.enrich, ) + self.get_onboarding_answers = async_to_raw_response_wrapper( + user.get_onboarding_answers, + ) self.info = async_to_raw_response_wrapper( user.info, ) self.refresh = async_to_raw_response_wrapper( user.refresh, ) + self.save_onboarding_answers = async_to_raw_response_wrapper( + user.save_onboarding_answers, + ) self.survey_submit = async_to_raw_response_wrapper( user.survey_submit, ) @@ -609,6 +728,7 @@ def stripe(self) -> AsyncStripeResourceWithRawResponse: @cached_property def api_keys(self) -> AsyncAPIKeysResourceWithRawResponse: + """All the accessible information about your account through our API""" return AsyncAPIKeysResourceWithRawResponse(self._user.api_keys) @@ -622,12 +742,18 @@ def __init__(self, user: UserResource) -> None: self.enrich = to_streamed_response_wrapper( user.enrich, ) + self.get_onboarding_answers = to_streamed_response_wrapper( + user.get_onboarding_answers, + ) self.info = to_streamed_response_wrapper( user.info, ) self.refresh = to_streamed_response_wrapper( user.refresh, ) + self.save_onboarding_answers = to_streamed_response_wrapper( + user.save_onboarding_answers, + ) self.survey_submit = to_streamed_response_wrapper( user.survey_submit, ) @@ -644,6 +770,7 @@ def stripe(self) -> StripeResourceWithStreamingResponse: @cached_property def api_keys(self) -> APIKeysResourceWithStreamingResponse: + """All the accessible information about your account through our API""" return APIKeysResourceWithStreamingResponse(self._user.api_keys) @@ -657,12 +784,18 @@ def __init__(self, user: AsyncUserResource) -> None: self.enrich = async_to_streamed_response_wrapper( user.enrich, ) + self.get_onboarding_answers = async_to_streamed_response_wrapper( + user.get_onboarding_answers, + ) self.info = async_to_streamed_response_wrapper( user.info, ) self.refresh = async_to_streamed_response_wrapper( user.refresh, ) + self.save_onboarding_answers = async_to_streamed_response_wrapper( + user.save_onboarding_answers, + ) self.survey_submit = async_to_streamed_response_wrapper( user.survey_submit, ) @@ -679,4 +812,5 @@ def stripe(self) -> AsyncStripeResourceWithStreamingResponse: @cached_property def api_keys(self) -> AsyncAPIKeysResourceWithStreamingResponse: + """All the accessible information about your account through our API""" return AsyncAPIKeysResourceWithStreamingResponse(self._user.api_keys) diff --git a/src/structify/resources/whitelabel.py b/src/structify/resources/whitelabel.py index 541facb7e..08cd5aa8e 100644 --- a/src/structify/resources/whitelabel.py +++ b/src/structify/resources/whitelabel.py @@ -5,6 +5,7 @@ import httpx from .._types import Body, Query, Headers, NoneType, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -20,6 +21,8 @@ class WhitelabelResource(SyncAPIResource): + """Whitelabeled service proxy endpoints""" + @cached_property def with_raw_response(self) -> WhitelabelResourceWithRawResponse: """ @@ -66,7 +69,7 @@ def estimate_cost( if not path: raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") return self._get( - f"/whitelabel/{service}/estimate-cost/{path}", + path_template("/whitelabel/{service}/estimate-cost/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -101,7 +104,7 @@ def proxy_get( raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._get( - f"/whitelabel/{service}/{path}", + path_template("/whitelabel/{service}/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -136,7 +139,7 @@ def proxy_post( raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/whitelabel/{service}/{path}", + path_template("/whitelabel/{service}/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -145,6 +148,8 @@ def proxy_post( class AsyncWhitelabelResource(AsyncAPIResource): + """Whitelabeled service proxy endpoints""" + @cached_property def with_raw_response(self) -> AsyncWhitelabelResourceWithRawResponse: """ @@ -191,7 +196,7 @@ async def estimate_cost( if not path: raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") return await self._get( - f"/whitelabel/{service}/estimate-cost/{path}", + path_template("/whitelabel/{service}/estimate-cost/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -226,7 +231,7 @@ async def proxy_get( raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._get( - f"/whitelabel/{service}/{path}", + path_template("/whitelabel/{service}/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -261,7 +266,7 @@ async def proxy_post( raise ValueError(f"Expected a non-empty value for `path` but received {path!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/whitelabel/{service}/{path}", + path_template("/whitelabel/{service}/{path}", service=service, path=path), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/wiki.py b/src/structify/resources/wiki.py index 3288974ea..85e6d0b43 100644 --- a/src/structify/resources/wiki.py +++ b/src/structify/resources/wiki.py @@ -8,7 +8,7 @@ from ..types import wiki_create_params, wiki_update_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -26,6 +26,8 @@ class WikiResource(SyncAPIResource): + """Team wiki page management endpoints""" + @cached_property def with_raw_response(self) -> WikiResourceWithRawResponse: """ @@ -72,7 +74,7 @@ def create( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._post( - f"/team/{team_id}/wiki", + path_template("/team/{team_id}/wiki", team_id=team_id), body=maybe_transform( { "markdown": markdown, @@ -117,7 +119,7 @@ def update( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return self._put( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), body=maybe_transform( { "markdown": markdown, @@ -156,7 +158,7 @@ def list( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return self._get( - f"/team/{team_id}/wiki", + path_template("/team/{team_id}/wiki", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -191,7 +193,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -225,7 +227,7 @@ def get( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return self._get( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -234,6 +236,8 @@ def get( class AsyncWikiResource(AsyncAPIResource): + """Team wiki page management endpoints""" + @cached_property def with_raw_response(self) -> AsyncWikiResourceWithRawResponse: """ @@ -280,7 +284,7 @@ async def create( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._post( - f"/team/{team_id}/wiki", + path_template("/team/{team_id}/wiki", team_id=team_id), body=await async_maybe_transform( { "markdown": markdown, @@ -325,7 +329,7 @@ async def update( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return await self._put( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), body=await async_maybe_transform( { "markdown": markdown, @@ -364,7 +368,7 @@ async def list( if not team_id: raise ValueError(f"Expected a non-empty value for `team_id` but received {team_id!r}") return await self._get( - f"/team/{team_id}/wiki", + path_template("/team/{team_id}/wiki", team_id=team_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -399,7 +403,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -433,7 +437,7 @@ async def get( if not slug: raise ValueError(f"Expected a non-empty value for `slug` but received {slug!r}") return await self._get( - f"/team/{team_id}/wiki/{slug}", + path_template("/team/{team_id}/wiki/{slug}", team_id=team_id, slug=slug), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/resources/workflow_schedule.py b/src/structify/resources/workflow_schedule.py index 111c2d17e..740128e23 100644 --- a/src/structify/resources/workflow_schedule.py +++ b/src/structify/resources/workflow_schedule.py @@ -13,7 +13,7 @@ workflow_schedule_get_sessions_params, ) from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -77,7 +77,7 @@ def create( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return self._post( - f"/workflow-schedule/{chat_session_id}", + path_template("/workflow-schedule/{chat_session_id}", chat_session_id=chat_session_id), body=maybe_transform( { "name": name, @@ -120,7 +120,7 @@ def update( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return self._put( - f"/workflow-schedule/{schedule_id}", + path_template("/workflow-schedule/{schedule_id}", schedule_id=schedule_id), body=maybe_transform( { "cron_schedule": cron_schedule, @@ -161,7 +161,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/workflow-schedule/{schedule_id}", + path_template("/workflow-schedule/{schedule_id}", schedule_id=schedule_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -192,7 +192,7 @@ def get( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return self._get( - f"/workflow-schedule/{chat_session_id}", + path_template("/workflow-schedule/{chat_session_id}", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -243,7 +243,7 @@ def get_sessions( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return self._post( - f"/workflow-schedule/{schedule_id}/sessions", + path_template("/workflow-schedule/{schedule_id}/sessions", schedule_id=schedule_id), body=maybe_transform( { "limit": limit, @@ -282,7 +282,7 @@ def pause( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return self._patch( - f"/workflow-schedule/{schedule_id}/pause", + path_template("/workflow-schedule/{schedule_id}/pause", schedule_id=schedule_id), body=maybe_transform({"paused": paused}, workflow_schedule_pause_params.WorkflowSchedulePauseParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -315,7 +315,7 @@ def run( raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/workflow-schedule/{schedule_id}/run", + path_template("/workflow-schedule/{schedule_id}/run", schedule_id=schedule_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -370,7 +370,7 @@ async def create( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return await self._post( - f"/workflow-schedule/{chat_session_id}", + path_template("/workflow-schedule/{chat_session_id}", chat_session_id=chat_session_id), body=await async_maybe_transform( { "name": name, @@ -413,7 +413,7 @@ async def update( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return await self._put( - f"/workflow-schedule/{schedule_id}", + path_template("/workflow-schedule/{schedule_id}", schedule_id=schedule_id), body=await async_maybe_transform( { "cron_schedule": cron_schedule, @@ -454,7 +454,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/workflow-schedule/{schedule_id}", + path_template("/workflow-schedule/{schedule_id}", schedule_id=schedule_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -485,7 +485,7 @@ async def get( if not chat_session_id: raise ValueError(f"Expected a non-empty value for `chat_session_id` but received {chat_session_id!r}") return await self._get( - f"/workflow-schedule/{chat_session_id}", + path_template("/workflow-schedule/{chat_session_id}", chat_session_id=chat_session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -536,7 +536,7 @@ async def get_sessions( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return await self._post( - f"/workflow-schedule/{schedule_id}/sessions", + path_template("/workflow-schedule/{schedule_id}/sessions", schedule_id=schedule_id), body=await async_maybe_transform( { "limit": limit, @@ -575,7 +575,7 @@ async def pause( if not schedule_id: raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") return await self._patch( - f"/workflow-schedule/{schedule_id}/pause", + path_template("/workflow-schedule/{schedule_id}/pause", schedule_id=schedule_id), body=await async_maybe_transform( {"paused": paused}, workflow_schedule_pause_params.WorkflowSchedulePauseParams ), @@ -610,7 +610,7 @@ async def run( raise ValueError(f"Expected a non-empty value for `schedule_id` but received {schedule_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/workflow-schedule/{schedule_id}/run", + path_template("/workflow-schedule/{schedule_id}/run", schedule_id=schedule_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/structify/types/__init__.py b/src/structify/types/__init__.py index 31412756e..636201a5a 100644 --- a/src/structify/types/__init__.py +++ b/src/structify/types/__init__.py @@ -15,8 +15,11 @@ from .dashboard import Dashboard as Dashboard from .team_role import TeamRole as TeamRole from .user_info import UserInfo as UserInfo +from .viz_param import VizParam as VizParam +from .viz_query import VizQuery as VizQuery from .wiki_page import WikiPage as WikiPage from .chat_event import ChatEvent as ChatEvent +from .viz_figure import VizFigure as VizFigure from .chat_prompt import ChatPrompt as ChatPrompt from .granularity import Granularity as Granularity from .table_param import TableParam as TableParam @@ -29,10 +32,13 @@ from .relationship import Relationship as Relationship from .workflow_dag import WorkflowDag as WorkflowDag from .chat_template import ChatTemplate as ChatTemplate +from .message_param import MessageParam as MessageParam from .property_type import PropertyType as PropertyType -from .tool_metadata import ToolMetadata as ToolMetadata +from .dashboard_item import DashboardItem as DashboardItem from .dashboard_page import DashboardPage as DashboardPage +from .dashboard_spec import DashboardSpec as DashboardSpec from .job_event_body import JobEventBody as JobEventBody +from .phase_activity import PhaseActivity as PhaseActivity from .project_member import ProjectMember as ProjectMember from .strategy_param import StrategyParam as StrategyParam from .team_with_role import TeamWithRole as TeamWithRole @@ -49,9 +55,17 @@ from .node_spec_param import NodeSpecParam as NodeSpecParam from .tool_invocation import ToolInvocation as ToolInvocation from .usage_group_key import UsageGroupKey as UsageGroupKey +from .viz_figure_kind import VizFigureKind as VizFigureKind +from .viz_param_param import VizParamParam as VizParamParam +from .viz_query_param import VizQueryParam as VizQueryParam from .chat_copy_params import ChatCopyParams as ChatCopyParams +from .datahub_progress import DatahubProgress as DatahubProgress +from .job_get_response import JobGetResponse as JobGetResponse from .save_requirement import SaveRequirement as SaveRequirement +from .viz_date_control import VizDateControl as VizDateControl +from .viz_figure_param import VizFigureParam as VizFigureParam from .workflow_session import WorkflowSession as WorkflowSession +from .chat_prompt_param import ChatPromptParam as ChatPromptParam from .chat_session_role import ChatSessionRole as ChatSessionRole from .connector_catalog import ConnectorCatalog as ConnectorCatalog from .connector_summary import ConnectorSummary as ConnectorSummary @@ -61,14 +75,17 @@ from .get_team_response import GetTeamResponse as GetTeamResponse from .job_list_response import JobListResponse as JobListResponse from .job_status_params import JobStatusParams as JobStatusParams +from .template_question import TemplateQuestion as TemplateQuestion from .user_usage_params import UserUsageParams as UserUsageParams from .workflow_node_log import WorkflowNodeLog as WorkflowNodeLog from .connector_category import ConnectorCategory as ConnectorCategory +from .datahub_secret_map import DatahubSecretMap as DatahubSecretMap from .dataset_descriptor import DatasetDescriptor as DatasetDescriptor from .dataset_get_params import DatasetGetParams as DatasetGetParams from .entity_view_params import EntityViewParams as EntityViewParams from .exploration_status import ExplorationStatus as ExplorationStatus from .merge_config_param import MergeConfigParam as MergeConfigParam +from .onboarding_answers import OnboardingAnswers as OnboardingAnswers from .parquet_edit_param import ParquetEditParam as ParquetEditParam from .project_visibility import ProjectVisibility as ProjectVisibility from .relationship_param import RelationshipParam as RelationshipParam @@ -81,6 +98,9 @@ from .team_update_params import TeamUpdateParams as TeamUpdateParams from .user_enrich_params import UserEnrichParams as UserEnrichParams from .user_update_params import UserUpdateParams as UserUpdateParams +from .viz_control_option import VizControlOption as VizControlOption +from .viz_number_control import VizNumberControl as VizNumberControl +from .viz_string_control import VizStringControl as VizStringControl from .wiki_create_params import WikiCreateParams as WikiCreateParams from .wiki_list_response import WikiListResponse as WikiListResponse from .wiki_update_params import WikiUpdateParams as WikiUpdateParams @@ -96,10 +116,12 @@ from .slack_events_params import SlackEventsParams as SlackEventsParams from .user_refresh_params import UserRefreshParams as UserRefreshParams from .user_usage_response import UserUsageResponse as UserUsageResponse +from .viz_boolean_control import VizBooleanControl as VizBooleanControl from .workflow_run_params import WorkflowRunParams as WorkflowRunParams from .connector_table_info import ConnectorTableInfo as ConnectorTableInfo from .create_team_response import CreateTeamResponse as CreateTeamResponse from .dashboard_page_param import DashboardPageParam as DashboardPageParam +from .dashboard_spec_param import DashboardSpecParam as DashboardSpecParam from .dataset_get_response import DatasetGetResponse as DatasetGetResponse from .dataset_match_params import DatasetMatchParams as DatasetMatchParams from .document_list_params import DocumentListParams as DocumentListParams @@ -109,6 +131,7 @@ from .entity_verify_params import EntityVerifyParams as EntityVerifyParams from .entity_view_response import EntityViewResponse as EntityViewResponse from .exploration_phase_id import ExplorationPhaseID as ExplorationPhaseID +from .exploration_progress import ExplorationProgress as ExplorationProgress from .list_tables_response import ListTablesResponse as ListTablesResponse from .project_get_response import ProjectGetResponse as ProjectGetResponse from .scrape_list_response import ScrapeListResponse as ScrapeListResponse @@ -131,9 +154,12 @@ from .project_update_params import ProjectUpdateParams as ProjectUpdateParams from .sandbox_list_response import SandboxListResponse as SandboxListResponse from .update_table_response import UpdateTableResponse as UpdateTableResponse +from .viz_date_control_type import VizDateControlType as VizDateControlType +from .viz_figure_definition import VizFigureDefinition as VizFigureDefinition from .workflow_session_edge import WorkflowSessionEdge as WorkflowSessionEdge from .workflow_session_node import WorkflowSessionNode as WorkflowSessionNode from .chat_load_files_params import ChatLoadFilesParams as ChatLoadFilesParams +from .compress_chat_response import CompressChatResponse as CompressChatResponse from .connector_get_response import ConnectorGetResponse as ConnectorGetResponse from .connector_with_secrets import ConnectorWithSecrets as ConnectorWithSecrets from .credits_usage_response import CreditsUsageResponse as CreditsUsageResponse @@ -153,6 +179,7 @@ from .scrape_scrape_response import ScrapeScrapeResponse as ScrapeScrapeResponse from .structure_pdf_response import StructurePdfResponse as StructurePdfResponse from .team_add_member_params import TeamAddMemberParams as TeamAddMemberParams +from .viz_date_control_param import VizDateControlParam as VizDateControlParam from .workflow_schedule_info import WorkflowScheduleInfo as WorkflowScheduleInfo from .connector_create_params import ConnectorCreateParams as ConnectorCreateParams from .connector_explorer_chat import ConnectorExplorerChat as ConnectorExplorerChat @@ -163,20 +190,30 @@ from .entity_add_batch_params import EntityAddBatchParams as EntityAddBatchParams from .entity_list_jobs_params import EntityListJobsParams as EntityListJobsParams from .entity_summarize_params import EntitySummarizeParams as EntitySummarizeParams -from .explore_status_response import ExploreStatusResponse as ExploreStatusResponse from .get_job_events_response import GetJobEventsResponse as GetJobEventsResponse -from .chat_delete_files_params import ChatDeleteFilesParams as ChatDeleteFilesParams +from .template_question_param import TemplateQuestionParam as TemplateQuestionParam +from .trigger_review_response import TriggerReviewResponse as TriggerReviewResponse +from .viz_number_control_type import VizNumberControlType as VizNumberControlType +from .viz_string_control_type import VizStringControlType as VizStringControlType from .chat_load_files_response import ChatLoadFilesResponse as ChatLoadFilesResponse from .connector_explore_params import ConnectorExploreParams as ConnectorExploreParams from .connector_store_response import ConnectorStoreResponse as ConnectorStoreResponse +from .datahub_secret_map_param import DatahubSecretMapParam as DatahubSecretMapParam from .dataset_descriptor_param import DatasetDescriptorParam as DatasetDescriptorParam from .document_download_params import DocumentDownloadParams as DocumentDownloadParams from .entity_derive_all_params import EntityDeriveAllParams as EntityDeriveAllParams from .entity_get_merges_params import EntityGetMergesParams as EntityGetMergesParams +from .list_dashboards_response import ListDashboardsResponse as ListDashboardsResponse from .match_create_jobs_params import MatchCreateJobsParams as MatchCreateJobsParams +from .onboarding_answers_param import OnboardingAnswersParam as OnboardingAnswersParam from .refresh_session_response import RefreshSessionResponse as RefreshSessionResponse from .session_kill_jobs_params import SessionKillJobsParams as SessionKillJobsParams +from .simulate_prompt_response import SimulatePromptResponse as SimulatePromptResponse from .team_subscription_status import TeamSubscriptionStatus as TeamSubscriptionStatus +from .viz_boolean_control_type import VizBooleanControlType as VizBooleanControlType +from .viz_control_option_param import VizControlOptionParam as VizControlOptionParam +from .viz_number_control_param import VizNumberControlParam as VizNumberControlParam +from .viz_string_control_param import VizStringControlParam as VizStringControlParam from .wiki_connector_reference import WikiConnectorReference as WikiConnectorReference from .chat_list_sessions_params import ChatListSessionsParams as ChatListSessionsParams from .code_generate_code_params import CodeGenerateCodeParams as CodeGenerateCodeParams @@ -188,21 +225,21 @@ from .exploration_runs_response import ExplorationRunsResponse as ExplorationRunsResponse from .get_chat_session_response import GetChatSessionResponse as GetChatSessionResponse from .get_dependencies_response import GetDependenciesResponse as GetDependenciesResponse -from .job_get_scrapers_response import JobGetScrapersResponse as JobGetScrapersResponse from .match_list_results_params import MatchListResultsParams as MatchListResultsParams from .session_get_events_params import SessionGetEventsParams as SessionGetEventsParams from .slack_event_payload_param import SlackEventPayloadParam as SlackEventPayloadParam from .team_credits_usage_params import TeamCreditsUsageParams as TeamCreditsUsageParams from .user_survey_submit_params import UserSurveySubmitParams as UserSurveySubmitParams +from .viz_boolean_control_param import VizBooleanControlParam as VizBooleanControlParam from .wiki_page_with_references import WikiPageWithReferences as WikiPageWithReferences from .accept_invitation_response import AcceptInvitationResponse as AcceptInvitationResponse from .admin_issue_found_response import AdminIssueFoundResponse as AdminIssueFoundResponse from .chat_add_git_commit_params import ChatAddGitCommitParams as ChatAddGitCommitParams from .chat_create_session_params import ChatCreateSessionParams as ChatCreateSessionParams -from .chat_delete_files_response import ChatDeleteFilesResponse as ChatDeleteFilesResponse from .chat_session_with_messages import ChatSessionWithMessages as ChatSessionWithMessages from .chat_update_session_params import ChatUpdateSessionParams as ChatUpdateSessionParams from .connector_credential_field import ConnectorCredentialField as ConnectorCredentialField +from .connector_explore_response import ConnectorExploreResponse as ConnectorExploreResponse from .connector_summaries_params import ConnectorSummariesParams as ConnectorSummariesParams from .create_match_jobs_response import CreateMatchJobsResponse as CreateMatchJobsResponse from .document_download_response import DocumentDownloadResponse as DocumentDownloadResponse @@ -216,6 +253,8 @@ from .update_visibility_response import UpdateVisibilityResponse as UpdateVisibilityResponse from .user_transactions_response import UserTransactionsResponse as UserTransactionsResponse from .admin_grant_access_response import AdminGrantAccessResponse as AdminGrantAccessResponse +from .chat_list_dashboards_params import ChatListDashboardsParams as ChatListDashboardsParams +from .chat_simulate_prompt_params import ChatSimulatePromptParams as ChatSimulatePromptParams from .dataset_add_property_params import DatasetAddPropertyParams as DatasetAddPropertyParams from .dataset_view_table_response import DatasetViewTableResponse as DatasetViewTableResponse from .entity_trigger_merge_params import EntityTriggerMergeParams as EntityTriggerMergeParams @@ -231,22 +270,30 @@ from .source_delete_entity_params import SourceDeleteEntityParams as SourceDeleteEntityParams from .structure_job_status_params import StructureJobStatusParams as StructureJobStatusParams from .update_member_role_response import UpdateMemberRoleResponse as UpdateMemberRoleResponse +from .viz_figure_definition_param import VizFigureDefinitionParam as VizFigureDefinitionParam +from .admin_report_critical_params import AdminReportCriticalParams as AdminReportCriticalParams from .chat_add_collaborator_params import ChatAddCollaboratorParams as ChatAddCollaboratorParams from .chat_add_git_commit_response import ChatAddGitCommitResponse as ChatAddGitCommitResponse from .chat_get_git_commit_response import ChatGetGitCommitResponse as ChatGetGitCommitResponse from .chat_list_templates_response import ChatListTemplatesResponse as ChatListTemplatesResponse +from .chat_load_input_files_params import ChatLoadInputFilesParams as ChatLoadInputFilesParams from .chat_revert_to_commit_params import ChatRevertToCommitParams as ChatRevertToCommitParams from .connector_summaries_response import ConnectorSummariesResponse as ConnectorSummariesResponse from .create_chat_session_response import CreateChatSessionResponse as CreateChatSessionResponse from .dataset_export_to_csv_params import DatasetExportToCsvParams as DatasetExportToCsvParams from .delete_chat_session_response import DeleteChatSessionResponse as DeleteChatSessionResponse from .entity_upload_parquet_params import EntityUploadParquetParams as EntityUploadParquetParams +from .sandbox_get_metrics_response import SandboxGetMetricsResponse as SandboxGetMetricsResponse from .sandbox_update_status_params import SandboxUpdateStatusParams as SandboxUpdateStatusParams from .structure_is_complete_params import StructureIsCompleteParams as StructureIsCompleteParams from .structure_run_async_response import StructureRunAsyncResponse as StructureRunAsyncResponse from .chat_admin_issue_found_params import ChatAdminIssueFoundParams as ChatAdminIssueFoundParams +from .chat_delete_input_file_params import ChatDeleteInputFileParams as ChatDeleteInputFileParams from .chat_update_visibility_params import ChatUpdateVisibilityParams as ChatUpdateVisibilityParams +from .chat_upload_input_file_params import ChatUploadInputFileParams as ChatUploadInputFileParams +from .code_apply_manual_edit_params import CodeApplyManualEditParams as CodeApplyManualEditParams from .connector_catalog_list_params import ConnectorCatalogListParams as ConnectorCatalogListParams +from .connector_table_path_response import ConnectorTablePathResponse as ConnectorTablePathResponse from .connector_update_table_params import ConnectorUpdateTableParams as ConnectorUpdateTableParams from .delete_schema_object_response import DeleteSchemaObjectResponse as DeleteSchemaObjectResponse from .delete_source_entity_response import DeleteSourceEntityResponse as DeleteSourceEntityResponse @@ -257,9 +304,12 @@ from .structure_job_status_response import StructureJobStatusResponse as StructureJobStatusResponse from .team_accept_invitation_params import TeamAcceptInvitationParams as TeamAcceptInvitationParams from .team_cancel_invitation_params import TeamCancelInvitationParams as TeamCancelInvitationParams +from .chat_list_input_files_response import ChatListInputFilesResponse as ChatListInputFilesResponse +from .chat_load_input_files_response import ChatLoadInputFilesResponse as ChatLoadInputFilesResponse from .chat_revert_to_commit_response import ChatRevertToCommitResponse as ChatRevertToCommitResponse from .connector_catalog_with_methods import ConnectorCatalogWithMethods as ConnectorCatalogWithMethods from .connector_create_secret_params import ConnectorCreateSecretParams as ConnectorCreateSecretParams +from .connector_list_stores_response import ConnectorListStoresResponse as ConnectorListStoresResponse from .connector_search_tables_params import ConnectorSearchTablesParams as ConnectorSearchTablesParams from .connector_update_column_params import ConnectorUpdateColumnParams as ConnectorUpdateColumnParams from .credits_usage_timeseries_point import CreditsUsageTimeseriesPoint as CreditsUsageTimeseriesPoint @@ -271,9 +321,12 @@ from .team_update_member_role_params import TeamUpdateMemberRoleParams as TeamUpdateMemberRoleParams from .workflow_node_execution_status import WorkflowNodeExecutionStatus as WorkflowNodeExecutionStatus from .workflow_schedule_pause_params import WorkflowSchedulePauseParams as WorkflowSchedulePauseParams +from .chat_delete_input_file_response import ChatDeleteInputFileResponse as ChatDeleteInputFileResponse from .chat_get_partial_chats_response import ChatGetPartialChatsResponse as ChatGetPartialChatsResponse +from .chat_upload_input_file_response import ChatUploadInputFileResponse as ChatUploadInputFileResponse from .connector_catalog_list_response import ConnectorCatalogListResponse as ConnectorCatalogListResponse from .entity_update_property_response import EntityUpdatePropertyResponse as EntityUpdatePropertyResponse +from .get_onboarding_answers_response import GetOnboardingAnswersResponse as GetOnboardingAnswersResponse from .session_edit_node_output_params import SessionEditNodeOutputParams as SessionEditNodeOutputParams from .workflow_schedule_create_params import WorkflowScheduleCreateParams as WorkflowScheduleCreateParams from .workflow_schedule_update_params import WorkflowScheduleUpdateParams as WorkflowScheduleUpdateParams @@ -282,9 +335,9 @@ from .connector_search_tables_response import ConnectorSearchTablesResponse as ConnectorSearchTablesResponse from .entity_add_relationship_response import EntityAddRelationshipResponse as EntityAddRelationshipResponse from .entity_get_local_subgraph_params import EntityGetLocalSubgraphParams as EntityGetLocalSubgraphParams -from .job_get_source_entities_response import JobGetSourceEntitiesResponse as JobGetSourceEntitiesResponse from .nango_list_integrations_response import NangoListIntegrationsResponse as NangoListIntegrationsResponse from .project_collaborator_input_param import ProjectCollaboratorInputParam as ProjectCollaboratorInputParam +from .save_onboarding_answers_response import SaveOnboardingAnswersResponse as SaveOnboardingAnswersResponse from .connector_auth_method_with_fields import ConnectorAuthMethodWithFields as ConnectorAuthMethodWithFields from .dataset_reorder_properties_params import DatasetReorderPropertiesParams as DatasetReorderPropertiesParams from .dataset_set_primary_column_params import DatasetSetPrimaryColumnParams as DatasetSetPrimaryColumnParams @@ -306,13 +359,13 @@ from .structure_find_relationship_params import StructureFindRelationshipParams as StructureFindRelationshipParams from .workflow_schedule_get_all_response import WorkflowScheduleGetAllResponse as WorkflowScheduleGetAllResponse from .chat_update_session_favorite_params import ChatUpdateSessionFavoriteParams as ChatUpdateSessionFavoriteParams -from .connector_list_with_snippets_params import ConnectorListWithSnippetsParams as ConnectorListWithSnippetsParams from .dataset_view_relationships_response import DatasetViewRelationshipsResponse as DatasetViewRelationshipsResponse from .delete_source_relationship_response import DeleteSourceRelationshipResponse as DeleteSourceRelationshipResponse from .entity_get_source_entities_response import EntityGetSourceEntitiesResponse as EntityGetSourceEntitiesResponse from .session_request_confirmation_params import SessionRequestConfirmationParams as SessionRequestConfirmationParams from .session_update_node_progress_params import SessionUpdateNodeProgressParams as SessionUpdateNodeProgressParams from .structure_enhance_property_response import StructureEnhancePropertyResponse as StructureEnhancePropertyResponse +from .user_save_onboarding_answers_params import UserSaveOnboardingAnswersParams as UserSaveOnboardingAnswersParams from .connector_add_schema_object_response import ConnectorAddSchemaObjectResponse as ConnectorAddSchemaObjectResponse from .dataset_enrichment_progress_response import DatasetEnrichmentProgressResponse as DatasetEnrichmentProgressResponse from .structure_find_relationship_response import StructureFindRelationshipResponse as StructureFindRelationshipResponse @@ -325,6 +378,9 @@ from .structure_enhance_relationship_params import ( StructureEnhanceRelationshipParams as StructureEnhanceRelationshipParams, ) +from .upload_dashboard_layout_request_param import ( + UploadDashboardLayoutRequestParam as UploadDashboardLayoutRequestParam, +) from .workflow_schedule_get_sessions_params import ( WorkflowScheduleGetSessionsParams as WorkflowScheduleGetSessionsParams, ) @@ -343,12 +399,18 @@ from .structure_enhance_relationship_response import ( StructureEnhanceRelationshipResponse as StructureEnhanceRelationshipResponse, ) +from .connector_upload_datahub_artifact_params import ( + ConnectorUploadDatahubArtifactParams as ConnectorUploadDatahubArtifactParams, +) from .chat_copy_node_output_by_code_hash_params import ( ChatCopyNodeOutputByCodeHashParams as ChatCopyNodeOutputByCodeHashParams, ) from .dataset_count_missing_embeddings_response import ( DatasetCountMissingEmbeddingsResponse as DatasetCountMissingEmbeddingsResponse, ) +from .connector_download_datahub_artifact_params import ( + ConnectorDownloadDatahubArtifactParams as ConnectorDownloadDatahubArtifactParams, +) from .chat_copy_node_output_by_code_hash_response import ( ChatCopyNodeOutputByCodeHashResponse as ChatCopyNodeOutputByCodeHashResponse, ) diff --git a/src/structify/types/admin/__init__.py b/src/structify/types/admin/__init__.py index 5fa1433e9..8422f8b82 100644 --- a/src/structify/types/admin/__init__.py +++ b/src/structify/types/admin/__init__.py @@ -7,31 +7,38 @@ from .job_list_params import JobListParams as JobListParams from .team_list_params import TeamListParams as TeamListParams from .job_delete_params import JobDeleteParams as JobDeleteParams +from .job_list_response import JobListResponse as JobListResponse +from .team_list_response import TeamListResponse as TeamListResponse from .user_create_params import UserCreateParams as UserCreateParams from .user_list_response import UserListResponse as UserListResponse from .sandbox_list_params import SandboxListParams as SandboxListParams from .admin_dataset_return import AdminDatasetReturn as AdminDatasetReturn from .impersonate_response import ImpersonateResponse as ImpersonateResponse +from .datahub_ingestion_key import DatahubIngestionKey as DatahubIngestionKey from .extend_trial_response import ExtendTrialResponse as ExtendTrialResponse from .user_get_stats_params import UserGetStatsParams as UserGetStatsParams from .connector_clone_params import ConnectorCloneParams as ConnectorCloneParams +from .datahub_ingestion_type import DatahubIngestionType as DatahubIngestionType from .expire_grants_response import ExpireGrantsResponse as ExpireGrantsResponse from .grant_credits_response import GrantCreditsResponse as GrantCreditsResponse from .team_add_member_params import TeamAddMemberParams as TeamAddMemberParams +from .job_kill_by_user_params import JobKillByUserParams as JobKillByUserParams from .user_get_stats_response import UserGetStatsResponse as UserGetStatsResponse from .user_impersonate_params import UserImpersonateParams as UserImpersonateParams -from .admin_list_jobs_response import AdminListJobsResponse as AdminListJobsResponse +from .connector_clone_response import ConnectorCloneResponse as ConnectorCloneResponse from .dataset_get_by_id_params import DatasetGetByIDParams as DatasetGetByIDParams +from .job_concurrency_response import JobConcurrencyResponse as JobConcurrencyResponse from .team_extend_trial_params import TeamExtendTrialParams as TeamExtendTrialParams from .admin_add_member_response import AdminAddMemberResponse as AdminAddMemberResponse from .admin_teams_list_response import AdminTeamsListResponse as AdminTeamsListResponse from .chat_template_list_params import ChatTemplateListParams as ChatTemplateListParams -from .clone_connectors_response import CloneConnectorsResponse as CloneConnectorsResponse +from .job_kill_by_user_response import JobKillByUserResponse as JobKillByUserResponse from .team_expire_grants_params import TeamExpireGrantsParams as TeamExpireGrantsParams from .team_grant_credits_params import TeamGrantCreditsParams as TeamGrantCreditsParams from .team_remove_member_params import TeamRemoveMemberParams as TeamRemoveMemberParams from .admin_delete_jobs_response import AdminDeleteJobsResponse as AdminDeleteJobsResponse from .clone_connector_item_param import CloneConnectorItemParam as CloneConnectorItemParam +from .job_running_stats_response import JobRunningStatsResponse as JobRunningStatsResponse from .admin_list_members_response import AdminListMembersResponse as AdminListMembersResponse from .chat_template_create_params import ChatTemplateCreateParams as ChatTemplateCreateParams from .chat_template_list_response import ChatTemplateListResponse as ChatTemplateListResponse @@ -41,13 +48,17 @@ from .create_subscription_response import CreateSubscriptionResponse as CreateSubscriptionResponse from .functional_test_create_params import FunctionalTestCreateParams as FunctionalTestCreateParams from .functional_test_list_response import FunctionalTestListResponse as FunctionalTestListResponse +from .job_update_concurrency_params import JobUpdateConcurrencyParams as JobUpdateConcurrencyParams +from .admin_list_connectors_response import AdminListConnectorsResponse as AdminListConnectorsResponse from .update_seats_override_response import UpdateSeatsOverrideResponse as UpdateSeatsOverrideResponse +from .job_update_concurrency_response import JobUpdateConcurrencyResponse as JobUpdateConcurrencyResponse from .team_cancel_subscription_params import TeamCancelSubscriptionParams as TeamCancelSubscriptionParams from .team_create_subscription_params import TeamCreateSubscriptionParams as TeamCreateSubscriptionParams from .functional_test_link_chat_params import FunctionalTestLinkChatParams as FunctionalTestLinkChatParams from .functional_test_results_response import FunctionalTestResultsResponse as FunctionalTestResultsResponse from .team_update_seats_override_params import TeamUpdateSeatsOverrideParams as TeamUpdateSeatsOverrideParams from .functional_test_get_results_params import FunctionalTestGetResultsParams as FunctionalTestGetResultsParams +from .connector_set_datahub_config_params import ConnectorSetDatahubConfigParams as ConnectorSetDatahubConfigParams from .functional_test_update_results_params import ( FunctionalTestUpdateResultsParams as FunctionalTestUpdateResultsParams, ) diff --git a/src/structify/types/admin/admin_list_connectors_response.py b/src/structify/types/admin/admin_list_connectors_response.py new file mode 100644 index 000000000..6c4e75926 --- /dev/null +++ b/src/structify/types/admin/admin_list_connectors_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from ..connector import Connector + +__all__ = ["AdminListConnectorsResponse"] + + +class AdminListConnectorsResponse(BaseModel): + connectors: List[Connector] diff --git a/src/structify/types/admin/admin_teams_list_response.py b/src/structify/types/admin/admin_teams_list_response.py index 9344a3feb..0f3b7e799 100644 --- a/src/structify/types/admin/admin_teams_list_response.py +++ b/src/structify/types/admin/admin_teams_list_response.py @@ -31,6 +31,8 @@ class AdminTeamsListResponseGrant(BaseModel): starts_at: Optional[datetime] = None + stripe_event_id: Optional[str] = None + class AdminTeamsListResponseSubscription(BaseModel): has_active_subscription: bool diff --git a/src/structify/types/admin/chat_template_create_params.py b/src/structify/types/admin/chat_template_create_params.py index 9856cd691..5d4472c9c 100644 --- a/src/structify/types/admin/chat_template_create_params.py +++ b/src/structify/types/admin/chat_template_create_params.py @@ -2,8 +2,11 @@ from __future__ import annotations +from typing import Iterable from typing_extensions import Required, TypedDict +from ..template_question_param import TemplateQuestionParam + __all__ = ["ChatTemplateCreateParams"] @@ -18,4 +21,6 @@ class ChatTemplateCreateParams(TypedDict, total=False): is_active: Required[bool] + questions: Required[Iterable[TemplateQuestionParam]] + title: Required[str] diff --git a/src/structify/types/admin/chat_template_update_params.py b/src/structify/types/admin/chat_template_update_params.py index 2b807aa4c..7129486a6 100644 --- a/src/structify/types/admin/chat_template_update_params.py +++ b/src/structify/types/admin/chat_template_update_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Optional +from typing import Iterable, Optional from typing_extensions import TypedDict +from ..template_question_param import TemplateQuestionParam + __all__ = ["ChatTemplateUpdateParams"] @@ -17,6 +19,8 @@ class ChatTemplateUpdateParams(TypedDict, total=False): is_active: Optional[bool] + questions: Optional[Iterable[TemplateQuestionParam]] + title: Optional[str] updated_by: Optional[str] diff --git a/src/structify/types/admin/connector_clone_params.py b/src/structify/types/admin/connector_clone_params.py index 0b2cd0195..b7511f31b 100644 --- a/src/structify/types/admin/connector_clone_params.py +++ b/src/structify/types/admin/connector_clone_params.py @@ -13,4 +13,8 @@ class ConnectorCloneParams(TypedDict, total=False): connectors: Required[Iterable[CloneConnectorItemParam]] + source_membership_id: Required[str] + + source_team_id: Required[str] + target_team_id: Required[str] diff --git a/src/structify/types/admin/clone_connectors_response.py b/src/structify/types/admin/connector_clone_response.py similarity index 72% rename from src/structify/types/admin/clone_connectors_response.py rename to src/structify/types/admin/connector_clone_response.py index 3f9e92177..3b3f86184 100644 --- a/src/structify/types/admin/clone_connectors_response.py +++ b/src/structify/types/admin/connector_clone_response.py @@ -5,8 +5,8 @@ from ..._models import BaseModel from ..connector import Connector -__all__ = ["CloneConnectorsResponse"] +__all__ = ["ConnectorCloneResponse"] -class CloneConnectorsResponse(BaseModel): +class ConnectorCloneResponse(BaseModel): connectors: List[Connector] diff --git a/src/structify/types/admin/connector_set_datahub_config_params.py b/src/structify/types/admin/connector_set_datahub_config_params.py new file mode 100644 index 000000000..19b947e9c --- /dev/null +++ b/src/structify/types/admin/connector_set_datahub_config_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from .datahub_ingestion_type import DatahubIngestionType +from ..datahub_secret_map_param import DatahubSecretMapParam + +__all__ = ["ConnectorSetDatahubConfigParams"] + + +class ConnectorSetDatahubConfigParams(TypedDict, total=False): + connector_id: Required[str] + + datahub_ingestion_type: Optional[DatahubIngestionType] + + datahub_secret_map: Optional[DatahubSecretMapParam] + """ + Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + """ diff --git a/src/structify/types/admin/datahub_ingestion_key.py b/src/structify/types/admin/datahub_ingestion_key.py new file mode 100644 index 000000000..4fd0234de --- /dev/null +++ b/src/structify/types/admin/datahub_ingestion_key.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["DatahubIngestionKey"] + +DatahubIngestionKey: TypeAlias = Literal[ + "host", + "port", + "database", + "username", + "password", + "account_id", + "warehouse", + "role", + "instance_url", + "access_token", + "project_id", + "credential_json", +] diff --git a/src/structify/types/admin/datahub_ingestion_type.py b/src/structify/types/admin/datahub_ingestion_type.py new file mode 100644 index 000000000..592994fdf --- /dev/null +++ b/src/structify/types/admin/datahub_ingestion_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["DatahubIngestionType"] + +DatahubIngestionType: TypeAlias = Literal["postgres", "snowflake", "salesforce", "hubspot", "bigquery"] diff --git a/src/structify/types/admin/job_concurrency_response.py b/src/structify/types/admin/job_concurrency_response.py new file mode 100644 index 000000000..8932c09d4 --- /dev/null +++ b/src/structify/types/admin/job_concurrency_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["JobConcurrencyResponse"] + + +class JobConcurrencyResponse(BaseModel): + id: int + + updated_at: datetime + + max_connector_explore_jobs: Optional[int] = None + + max_derive_jobs: Optional[int] = None + + max_match_jobs: Optional[int] = None + + max_pdf_jobs: Optional[int] = None + + max_scrape_jobs: Optional[int] = None + + max_total_jobs: Optional[int] = None + + max_web_jobs: Optional[int] = None diff --git a/src/structify/types/admin/job_kill_by_user_params.py b/src/structify/types/admin/job_kill_by_user_params.py new file mode 100644 index 000000000..26dc2f804 --- /dev/null +++ b/src/structify/types/admin/job_kill_by_user_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__ = ["JobKillByUserParams"] + + +class JobKillByUserParams(TypedDict, total=False): + user_id: Required[str] diff --git a/src/structify/types/admin/job_kill_by_user_response.py b/src/structify/types/admin/job_kill_by_user_response.py new file mode 100644 index 000000000..3754fe457 --- /dev/null +++ b/src/structify/types/admin/job_kill_by_user_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["JobKillByUserResponse"] + + +class JobKillByUserResponse(BaseModel): + killed_jobs: int diff --git a/src/structify/types/admin/job_list_params.py b/src/structify/types/admin/job_list_params.py index 150217f76..62f040440 100644 --- a/src/structify/types/admin/job_list_params.py +++ b/src/structify/types/admin/job_list_params.py @@ -2,36 +2,19 @@ from __future__ import annotations -from typing import Union, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo +from typing import Optional +from typing_extensions import Literal, TypedDict __all__ = ["JobListParams"] class JobListParams(TypedDict, total=False): - filter_test_users: Required[bool] - """ - Filter out jobs from test users (users with functional_test feature flag or - debug permission) - """ - - limit: Required[int] - """Number of results to return""" - - offset: Required[int] - """Pagination offset""" + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] - dataset_id: Optional[str] - """Dataset ID to optionally filter jobs by""" + limit: int - seeded_kg_search_term: Optional[str] - """Seeded kg search term""" - - since: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - """List since a specific timestamp""" + offset: int status: Optional[Literal["Queued", "Running", "Completed", "Failed"]] - """Status to optionally filter jobs by""" + + user_id: Optional[str] diff --git a/src/structify/types/admin/admin_list_jobs_response.py b/src/structify/types/admin/job_list_response.py similarity index 82% rename from src/structify/types/admin/admin_list_jobs_response.py rename to src/structify/types/admin/job_list_response.py index eb52fa0f0..523c2310d 100644 --- a/src/structify/types/admin/admin_list_jobs_response.py +++ b/src/structify/types/admin/job_list_response.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional +from datetime import datetime from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo @@ -11,7 +12,7 @@ from ..exploration_phase_id import ExplorationPhaseID __all__ = [ - "AdminListJobsResponse", + "JobListResponse", "Parameters", "ParametersStructuringInput", "ParametersStructuringInputAgent", @@ -25,6 +26,8 @@ "ParametersStructuringInputScrapeFromURLPropertyScrapeFromURLProperty", "ParametersStructuringInputScrapeURL", "ParametersStructuringInputScrapeURLScrapeURL", + "ParametersStructuringInputDatahubIngestion", + "ParametersStructuringInputDatahubIngestionDatahubIngestion", "ParametersStructuringInputConnectorExploration", "ParametersStructuringInputConnectorExplorationConnectorExploration", ] @@ -94,6 +97,18 @@ class ParametersStructuringInputScrapeURL(BaseModel): scrape_url: ParametersStructuringInputScrapeURLScrapeURL = FieldInfo(alias="ScrapeUrl") +class ParametersStructuringInputDatahubIngestionDatahubIngestion(BaseModel): + connector_id: str + + exploration_run_id: str + + only_do_datahub: bool + + +class ParametersStructuringInputDatahubIngestion(BaseModel): + datahub_ingestion: ParametersStructuringInputDatahubIngestionDatahubIngestion = FieldInfo(alias="DatahubIngestion") + + class ParametersStructuringInputConnectorExplorationConnectorExploration(BaseModel): connector_id: str @@ -106,8 +121,7 @@ class ParametersStructuringInputConnectorExplorationConnectorExploration(BaseMod exploration_run_id: str - stage: Literal["both", "ingestion", "annotation"] - """Which exploration stage to run""" + strategy: Literal["full", "diff"] class ParametersStructuringInputConnectorExploration(BaseModel): @@ -121,6 +135,7 @@ class ParametersStructuringInputConnectorExploration(BaseModel): ParametersStructuringInputTransformationPrompt, ParametersStructuringInputScrapeFromURLProperty, ParametersStructuringInputScrapeURL, + ParametersStructuringInputDatahubIngestion, ParametersStructuringInputConnectorExploration, ] @@ -130,29 +145,39 @@ class Parameters(BaseModel): extraction_criteria: List[SaveRequirement] - seeded_kg: KnowledgeGraph - """ - Knowledge graph info structured to deserialize and display in the same format - that the LLM outputs. Also the first representation of an LLM output in the - pipeline from raw tool output to being merged into a DB - """ - structuring_input: ParametersStructuringInput instructions: Optional[str] = None model: Optional[str] = None + seeded_kg: Optional[KnowledgeGraph] = None + """ + Knowledge graph info structured to deserialize and display in the same format + that the LLM outputs. Also the first representation of an LLM output in the + pipeline from raw tool output to being merged into a DB + """ + -class AdminListJobsResponse(BaseModel): +class JobListResponse(BaseModel): id: str - dataset_id: str + created_at: datetime - job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"] + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] status: Literal["Queued", "Running", "Completed", "Failed"] user_id: str + dataset_id: Optional[str] = None + + message: Optional[str] = None + parameters: Optional[Parameters] = None + + reason: Optional[str] = None + + run_started_time: Optional[datetime] = None + + run_time_milliseconds: Optional[int] = None diff --git a/src/structify/types/admin/job_running_stats_response.py b/src/structify/types/admin/job_running_stats_response.py new file mode 100644 index 000000000..8f0d2f748 --- /dev/null +++ b/src/structify/types/admin/job_running_stats_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel + +__all__ = ["JobRunningStatsResponse", "ByType", "ByUser"] + + +class ByType(BaseModel): + count: int + + job_type: str + + +class ByUser(BaseModel): + email: str + + queued: int + + running: int + + user_id: str + + +class JobRunningStatsResponse(BaseModel): + by_type: List[ByType] + + by_user: List[ByUser] + + completed_last_hour: int + + failed_last_hour: int + + total_queued: int + + total_running: int diff --git a/src/structify/types/admin/job_update_concurrency_params.py b/src/structify/types/admin/job_update_concurrency_params.py new file mode 100644 index 000000000..5cbbdc869 --- /dev/null +++ b/src/structify/types/admin/job_update_concurrency_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["JobUpdateConcurrencyParams"] + + +class JobUpdateConcurrencyParams(TypedDict, total=False): + max_connector_explore_jobs: Optional[int] + + max_derive_jobs: Optional[int] + + max_match_jobs: Optional[int] + + max_pdf_jobs: Optional[int] + + max_scrape_jobs: Optional[int] + + max_total_jobs: Optional[int] + + max_web_jobs: Optional[int] diff --git a/src/structify/types/admin/job_update_concurrency_response.py b/src/structify/types/admin/job_update_concurrency_response.py new file mode 100644 index 000000000..82b1ce3f3 --- /dev/null +++ b/src/structify/types/admin/job_update_concurrency_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["JobUpdateConcurrencyResponse"] + + +class JobUpdateConcurrencyResponse(BaseModel): + id: int + + updated_at: datetime + + max_connector_explore_jobs: Optional[int] = None + + max_derive_jobs: Optional[int] = None + + max_match_jobs: Optional[int] = None + + max_pdf_jobs: Optional[int] = None + + max_scrape_jobs: Optional[int] = None + + max_total_jobs: Optional[int] = None + + max_web_jobs: Optional[int] = None diff --git a/src/structify/types/admin/team_list_params.py b/src/structify/types/admin/team_list_params.py index e5cec336c..065bf3749 100644 --- a/src/structify/types/admin/team_list_params.py +++ b/src/structify/types/admin/team_list_params.py @@ -12,3 +12,5 @@ class TeamListParams(TypedDict, total=False): limit: Optional[int] offset: Optional[int] + + search: Optional[str] diff --git a/src/structify/types/admin/team_list_response.py b/src/structify/types/admin/team_list_response.py new file mode 100644 index 000000000..0c06da6ba --- /dev/null +++ b/src/structify/types/admin/team_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from ..._models import BaseModel +from .admin_teams_list_response import AdminTeamsListResponse + +__all__ = ["TeamListResponse"] + + +class TeamListResponse(BaseModel): + items: List[AdminTeamsListResponse] + + total_count: int diff --git a/src/structify/types/admin/user.py b/src/structify/types/admin/user.py index e4c6019d9..cc3fb4d99 100644 --- a/src/structify/types/admin/user.py +++ b/src/structify/types/admin/user.py @@ -40,7 +40,7 @@ class User(BaseModel): full_name: str - is_developer: bool + notify_for_interaction: bool permissions: List[Optional[Literal["labeler", "qa_labeler", "debug", "human_llm", "none"]]] diff --git a/src/structify/types/admin_report_critical_params.py b/src/structify/types/admin_report_critical_params.py new file mode 100644 index 000000000..5e036be4f --- /dev/null +++ b/src/structify/types/admin_report_critical_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__ = ["AdminReportCriticalParams"] + + +class AdminReportCriticalParams(TypedDict, total=False): + message: Required[str] diff --git a/src/structify/types/chat_copy_node_output_by_code_hash_response.py b/src/structify/types/chat_copy_node_output_by_code_hash_response.py index ca05ae006..dde2da91d 100644 --- a/src/structify/types/chat_copy_node_output_by_code_hash_response.py +++ b/src/structify/types/chat_copy_node_output_by_code_hash_response.py @@ -1,8 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Optional -from typing_extensions import TypeAlias + +from .._models import BaseModel __all__ = ["ChatCopyNodeOutputByCodeHashResponse"] -ChatCopyNodeOutputByCodeHashResponse: TypeAlias = Optional[str] + +class ChatCopyNodeOutputByCodeHashResponse(BaseModel): + cached_node_id: Optional[str] = None diff --git a/src/structify/types/chat_copy_params.py b/src/structify/types/chat_copy_params.py index 9e0070cb4..686312b2a 100644 --- a/src/structify/types/chat_copy_params.py +++ b/src/structify/types/chat_copy_params.py @@ -18,3 +18,5 @@ class ChatCopyParams(TypedDict, total=False): copy_inputs: bool project_id: Optional[str] + + template_id: Optional[str] diff --git a/src/structify/types/chat_create_session_params.py b/src/structify/types/chat_create_session_params.py index b7c894703..61b16071f 100644 --- a/src/structify/types/chat_create_session_params.py +++ b/src/structify/types/chat_create_session_params.py @@ -16,8 +16,6 @@ class ChatCreateSessionParams(TypedDict, total=False): ephemeral: Optional[bool] - initial_message: Optional[str] - project_id: Optional[str] @@ -50,7 +48,9 @@ class Config(TypedDict, total=False): "gemini.gemini-2.5-flash", "gemini.gemini-3-pro-preview", "gemini.gemini-3-flash-preview", + "gemini.gemini-3.1-flash-lite-preview", "vertex_anthropic.claude-sonnet-4-5-vertex", + "vertex_anthropic.claude-opus-4-5-vertex", ] ] """LLM model keys available in the system. Format: .""" diff --git a/src/structify/types/chat_delete_files_params.py b/src/structify/types/chat_delete_input_file_params.py similarity index 60% rename from src/structify/types/chat_delete_files_params.py rename to src/structify/types/chat_delete_input_file_params.py index ed4fcfadc..9b9c5e0e8 100644 --- a/src/structify/types/chat_delete_files_params.py +++ b/src/structify/types/chat_delete_input_file_params.py @@ -6,8 +6,8 @@ from .._types import SequenceNotStr -__all__ = ["ChatDeleteFilesParams"] +__all__ = ["ChatDeleteInputFileParams"] -class ChatDeleteFilesParams(TypedDict, total=False): - paths: Required[SequenceNotStr[str]] +class ChatDeleteInputFileParams(TypedDict, total=False): + filenames: Required[SequenceNotStr[str]] diff --git a/src/structify/types/chat_delete_files_response.py b/src/structify/types/chat_delete_input_file_response.py similarity index 62% rename from src/structify/types/chat_delete_files_response.py rename to src/structify/types/chat_delete_input_file_response.py index c075f48c7..b0c00de63 100644 --- a/src/structify/types/chat_delete_files_response.py +++ b/src/structify/types/chat_delete_input_file_response.py @@ -2,8 +2,8 @@ from .._models import BaseModel -__all__ = ["ChatDeleteFilesResponse"] +__all__ = ["ChatDeleteInputFileResponse"] -class ChatDeleteFilesResponse(BaseModel): +class ChatDeleteInputFileResponse(BaseModel): files_deleted: int diff --git a/src/structify/types/chat_event.py b/src/structify/types/chat_event.py index e44f40a4c..c6da66729 100644 --- a/src/structify/types/chat_event.py +++ b/src/structify/types/chat_event.py @@ -1,7 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Union, Optional -from typing_extensions import TypeAlias +from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo @@ -35,6 +35,9 @@ "AttachedFileAttachedFile", "ConnectorRequest", "ConnectorRequestConnectorRequest", + "UserInterrupted", + "IssueFound", + "IssueFoundIssueFound", ] @@ -144,6 +147,12 @@ class Question(BaseModel): class InternalErrorInternalError(BaseModel): message: str + error_kind: Optional[Literal["unknown", "context_limit", "rate_limited", "timeout", "connection_error"]] = None + """ + Categorizes the kind of internal error that occurred during LLM generation. This + allows the frontend to render appropriate error messages without regex matching. + """ + class InternalError(BaseModel): internal_error: InternalErrorInternalError = FieldInfo(alias="InternalError") @@ -185,6 +194,22 @@ class ConnectorRequest(BaseModel): connector_request: ConnectorRequestConnectorRequest = FieldInfo(alias="ConnectorRequest") +class UserInterrupted(BaseModel): + user_interrupted: object = FieldInfo(alias="UserInterrupted") + + +class IssueFoundIssueFound(BaseModel): + admin_override: bool + + description: str + + title: str + + +class IssueFound(BaseModel): + issue_found: IssueFoundIssueFound = FieldInfo(alias="IssueFound") + + ChatEvent: TypeAlias = Union[ TextMessage, Thinking, @@ -197,4 +222,6 @@ class ConnectorRequest(BaseModel): ReviewRequest, AttachedFile, ConnectorRequest, + UserInterrupted, + IssueFound, ] diff --git a/src/structify/types/chat_get_partial_chats_response.py b/src/structify/types/chat_get_partial_chats_response.py index f2fa66051..659af4c13 100644 --- a/src/structify/types/chat_get_partial_chats_response.py +++ b/src/structify/types/chat_get_partial_chats_response.py @@ -1,10 +1,21 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from datetime import datetime from typing_extensions import TypeAlias +from .._models import BaseModel from .chat_prompt import ChatPrompt -__all__ = ["ChatGetPartialChatsResponse"] +__all__ = ["ChatGetPartialChatsResponse", "ChatGetPartialChatsResponseItem"] -ChatGetPartialChatsResponse: TypeAlias = List[ChatPrompt] + +class ChatGetPartialChatsResponseItem(BaseModel): + chat_prompt: ChatPrompt + + created_at: datetime + + message_id: Optional[str] = None + + +ChatGetPartialChatsResponse: TypeAlias = List[ChatGetPartialChatsResponseItem] diff --git a/src/structify/types/chat_get_session_timeline_response.py b/src/structify/types/chat_get_session_timeline_response.py index e50cb2803..1d936f547 100644 --- a/src/structify/types/chat_get_session_timeline_response.py +++ b/src/structify/types/chat_get_session_timeline_response.py @@ -41,7 +41,7 @@ class TimelineMessage(BaseModel): content_proto: Optional[object] = None - git_commit_id: Optional[str] = None + git_hash: Optional[str] = None previous_message_id: Optional[str] = None diff --git a/src/structify/types/chat_list_dashboards_params.py b/src/structify/types/chat_list_dashboards_params.py new file mode 100644 index 000000000..bb0dadd3e --- /dev/null +++ b/src/structify/types/chat_list_dashboards_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +__all__ = ["ChatListDashboardsParams"] + + +class ChatListDashboardsParams(TypedDict, total=False): + commit_hash: Optional[str] + """Optional commit hash. If omitted, uses the chat session latest commit.""" diff --git a/src/structify/types/chat_list_input_files_response.py b/src/structify/types/chat_list_input_files_response.py new file mode 100644 index 000000000..f8597a2d8 --- /dev/null +++ b/src/structify/types/chat_list_input_files_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime +from typing_extensions import TypeAlias + +from .._models import BaseModel + +__all__ = ["ChatListInputFilesResponse", "ChatListInputFilesResponseItem"] + + +class ChatListInputFilesResponseItem(BaseModel): + chat_session_id: str + + content_type: str + + created_at: datetime + + file_size: int + + filename: str + + +ChatListInputFilesResponse: TypeAlias = List[ChatListInputFilesResponseItem] diff --git a/src/structify/types/chat_list_sessions_params.py b/src/structify/types/chat_list_sessions_params.py index ad0ab10d6..70db59561 100644 --- a/src/structify/types/chat_list_sessions_params.py +++ b/src/structify/types/chat_list_sessions_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict __all__ = ["ChatListSessionsParams"] @@ -12,8 +12,20 @@ class ChatListSessionsParams(TypedDict, total=False): team_id: Required[str] """Team ID to filter chat sessions""" + connector_id: Optional[str] + """Connector ID to filter chat sessions that use this connector""" + limit: Optional[int] """Maximum number of sessions to return (default: 50)""" + offset: Optional[int] + """Number of sessions to skip (default: 0)""" + project_id: Optional[str] """Project ID to filter chat sessions""" + + search: Optional[str] + """Search query to filter sessions by name (case-insensitive)""" + + tab: Optional[Literal["my_chats", "favorites", "shared", "team", "recents", "from_messaging"]] + """Tab filter for chat sessions""" diff --git a/src/structify/types/chat_load_input_files_params.py b/src/structify/types/chat_load_input_files_params.py new file mode 100644 index 000000000..ddc8dbd3a --- /dev/null +++ b/src/structify/types/chat_load_input_files_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["ChatLoadInputFilesParams"] + + +class ChatLoadInputFilesParams(TypedDict, total=False): + since: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] diff --git a/src/structify/types/chat_load_input_files_response.py b/src/structify/types/chat_load_input_files_response.py new file mode 100644 index 000000000..19c08da4a --- /dev/null +++ b/src/structify/types/chat_load_input_files_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["ChatLoadInputFilesResponse"] + + +class ChatLoadInputFilesResponse(BaseModel): + files: Dict[str, str] + + latest_timestamp: Optional[datetime] = None diff --git a/src/structify/types/chat_prompt.py b/src/structify/types/chat_prompt.py index 04c7a1fba..e89b2d303 100644 --- a/src/structify/types/chat_prompt.py +++ b/src/structify/types/chat_prompt.py @@ -7,7 +7,6 @@ from .message import Message from .._models import BaseModel -from .tool_metadata import ToolMetadata from .knowledge_graph import KnowledgeGraph from .save_requirement import SaveRequirement from .dataset_descriptor import DatasetDescriptor @@ -238,8 +237,6 @@ class Metadata(BaseModel): formatter_specific: MetadataFormatterSpecific - tool_metadata: List[ToolMetadata] - qa_potentially_sus_response: Optional[str] = None diff --git a/src/structify/types/chat_prompt_param.py b/src/structify/types/chat_prompt_param.py new file mode 100644 index 000000000..10d188a3b --- /dev/null +++ b/src/structify/types/chat_prompt_param.py @@ -0,0 +1,254 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import FileTypes, SequenceNotStr +from .._utils import PropertyInfo +from .message_param import MessageParam +from .knowledge_graph_param import KnowledgeGraphParam +from .save_requirement_param import SaveRequirementParam +from .dataset_descriptor_param import DatasetDescriptorParam + +__all__ = [ + "ChatPromptParam", + "DecodingParams", + "DecodingParamsParameter", + "DecodingParamsParameterMaxTokens", + "DecodingParamsParameterMaxCompletionTokens", + "DecodingParamsParameterTopP", + "DecodingParamsParameterRepeatWindow", + "DecodingParamsParameterRepeatPenalty", + "DecodingParamsParameterTemperature", + "DecodingParamsParameterStopTokens", + "DecodingParamsParameterLogitBias", + "DecodingParamsParameterFunctions", + "DecodingParamsParameterJsonValidator", + "DecodingParamsParameterRegexValidator", + "DecodingParamsParameterContextFreeGrammar", + "DecodingParamsParameterNumBeams", + "DecodingParamsParameterCrop", + "DecodingParamsParameterThinking", + "DecodingParamsParameterVerbosity", + "DecodingParamsParameterReasoningEffort", + "Metadata", + "MetadataFormatterSpecific", + "MetadataFormatterSpecificImageMeta", + "MetadataFormatterSpecificImageMetaImageMeta", + "MetadataFormatterSpecificWebMeta", + "MetadataFormatterSpecificWebMetaWebMeta", + "MetadataFormatterSpecificWebMetaWebMetaFlag", + "MetadataFormatterSpecificTextMeta", + "MetadataFormatterSpecificTextMetaTextMeta", + "MetadataFormatterSpecificScraperMeta", + "MetadataFormatterSpecificScraperMetaScraperMeta", +] + + +class DecodingParamsParameterMaxTokens(TypedDict, total=False): + max_tokens: Required[Annotated[int, PropertyInfo(alias="MaxTokens")]] + + +class DecodingParamsParameterMaxCompletionTokens(TypedDict, total=False): + max_completion_tokens: Required[Annotated[int, PropertyInfo(alias="MaxCompletionTokens")]] + + +class DecodingParamsParameterTopP(TypedDict, total=False): + top_p: Required[Annotated[float, PropertyInfo(alias="TopP")]] + + +class DecodingParamsParameterRepeatWindow(TypedDict, total=False): + repeat_window: Required[Annotated[int, PropertyInfo(alias="RepeatWindow")]] + + +class DecodingParamsParameterRepeatPenalty(TypedDict, total=False): + repeat_penalty: Required[Annotated[float, PropertyInfo(alias="RepeatPenalty")]] + + +class DecodingParamsParameterTemperature(TypedDict, total=False): + temperature: Required[Annotated[float, PropertyInfo(alias="Temperature")]] + + +class DecodingParamsParameterStopTokens(TypedDict, total=False): + stop_tokens: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="StopTokens")]] + + +class DecodingParamsParameterLogitBias(TypedDict, total=False): + logit_bias: Required[Annotated[Dict[str, float], PropertyInfo(alias="LogitBias")]] + + +class DecodingParamsParameterFunctions(TypedDict, total=False): + functions: Required[Annotated[Iterable[Dict[str, object]], PropertyInfo(alias="Functions")]] + + +class DecodingParamsParameterJsonValidator(TypedDict, total=False): + json_validator: Required[Annotated[Dict[str, object], PropertyInfo(alias="JsonValidator")]] + + +class DecodingParamsParameterRegexValidator(TypedDict, total=False): + regex_validator: Required[Annotated[str, PropertyInfo(alias="RegexValidator")]] + + +class DecodingParamsParameterContextFreeGrammar(TypedDict, total=False): + context_free_grammar: Required[Annotated[str, PropertyInfo(alias="ContextFreeGrammar")]] + + +class DecodingParamsParameterNumBeams(TypedDict, total=False): + num_beams: Required[Annotated[int, PropertyInfo(alias="NumBeams")]] + + +class DecodingParamsParameterCrop(TypedDict, total=False): + crop: Required[Annotated[bool, PropertyInfo(alias="Crop")]] + + +class DecodingParamsParameterThinking(TypedDict, total=False): + thinking: Required[Annotated[int, PropertyInfo(alias="Thinking")]] + """Thinking tokens for Claude 3.7. Contains the budget in tokens for thinking.""" + + +class DecodingParamsParameterVerbosity(TypedDict, total=False): + verbosity: Required[Annotated[Literal["low", "medium", "high"], PropertyInfo(alias="Verbosity")]] + + +class DecodingParamsParameterReasoningEffort(TypedDict, total=False): + reasoning_effort: Required[ + Annotated[Literal["low", "medium", "high", "minimal"], PropertyInfo(alias="ReasoningEffort")] + ] + + +DecodingParamsParameter: TypeAlias = Union[ + DecodingParamsParameterMaxTokens, + DecodingParamsParameterMaxCompletionTokens, + DecodingParamsParameterTopP, + DecodingParamsParameterRepeatWindow, + DecodingParamsParameterRepeatPenalty, + DecodingParamsParameterTemperature, + DecodingParamsParameterStopTokens, + DecodingParamsParameterLogitBias, + DecodingParamsParameterFunctions, + DecodingParamsParameterJsonValidator, + DecodingParamsParameterRegexValidator, + DecodingParamsParameterContextFreeGrammar, + DecodingParamsParameterNumBeams, + DecodingParamsParameterCrop, + DecodingParamsParameterThinking, + DecodingParamsParameterVerbosity, + DecodingParamsParameterReasoningEffort, +] + + +class DecodingParams(TypedDict, total=False): + parameters: Required[Iterable[DecodingParamsParameter]] + + +class MetadataFormatterSpecificImageMetaImageMeta(TypedDict, total=False): + image: Required[Optional[str]] + + document_name: Optional[str] + + document_page: Optional[int] + + ocr_content: Optional[str] + + +class MetadataFormatterSpecificImageMeta(TypedDict, total=False): + image_meta: Required[Annotated[MetadataFormatterSpecificImageMetaImageMeta, PropertyInfo(alias="ImageMeta")]] + + +class MetadataFormatterSpecificWebMetaWebMetaFlag(TypedDict, total=False): + aria_label: Required[Annotated[str, PropertyInfo(alias="ariaLabel")]] + + type: Required[str] + + x: Required[float] + + y: Required[float] + + height: float + + href: Optional[str] + + is_interactive: Annotated[Optional[bool], PropertyInfo(alias="isInteractive")] + + number: Optional[int] + """The number by which the flag is referred in image, prompt, and tool calls.""" + + text: str + + width: float + """ + The serde default here is to give us backwards compatibility it's fine for these + to be anything as long as the image isn't given since it won't regenerate. + """ + + +class MetadataFormatterSpecificWebMetaWebMeta(TypedDict, total=False): + flags: Required[Iterable[MetadataFormatterSpecificWebMetaWebMetaFlag]] + + url: Required[str] + + ocr_content: Optional[str] + + screenshot: Optional[FileTypes] + + +class MetadataFormatterSpecificWebMeta(TypedDict, total=False): + web_meta: Required[Annotated[MetadataFormatterSpecificWebMetaWebMeta, PropertyInfo(alias="WebMeta")]] + + +class MetadataFormatterSpecificTextMetaTextMeta(TypedDict, total=False): + text: Required[str] + + +class MetadataFormatterSpecificTextMeta(TypedDict, total=False): + text_meta: Required[Annotated[MetadataFormatterSpecificTextMetaTextMeta, PropertyInfo(alias="TextMeta")]] + + +class MetadataFormatterSpecificScraperMetaScraperMeta(TypedDict, total=False): + html_content: Required[str] + + url: Required[str] + + +class MetadataFormatterSpecificScraperMeta(TypedDict, total=False): + scraper_meta: Required[ + Annotated[MetadataFormatterSpecificScraperMetaScraperMeta, PropertyInfo(alias="ScraperMeta")] + ] + + +MetadataFormatterSpecific: TypeAlias = Union[ + MetadataFormatterSpecificImageMeta, + MetadataFormatterSpecificWebMeta, + MetadataFormatterSpecificTextMeta, + MetadataFormatterSpecificScraperMeta, +] + + +class Metadata(TypedDict, total=False): + """All metadata required to generate a prompt for the LLM""" + + dataset_descriptor: Required[DatasetDescriptorParam] + """A dataset is where you put multiple referential schemas. + + A dataset is a complete namespace where all references between schemas are held + within the dataset. + """ + + extracted_entities: Required[Iterable[KnowledgeGraphParam]] + + extraction_criteria: Required[Iterable[SaveRequirementParam]] + + formatter_specific: Required[MetadataFormatterSpecific] + + qa_potentially_sus_response: Optional[str] + + +class ChatPromptParam(TypedDict, total=False): + decoding_params: Required[DecodingParams] + + messages: Required[Iterable[MessageParam]] + + metadata: Required[Metadata] + """All metadata required to generate a prompt for the LLM""" diff --git a/src/structify/types/chat_session.py b/src/structify/types/chat_session.py index a3e7305c9..70c8d9dfd 100644 --- a/src/structify/types/chat_session.py +++ b/src/structify/types/chat_session.py @@ -36,6 +36,10 @@ class ChatSession(BaseModel): config_proto: Optional[object] = None + instantiated_from_template_id: Optional[str] = None + + message_head: Optional[str] = None + name: Optional[str] = None project_id: Optional[str] = None diff --git a/src/structify/types/chat_session_with_messages.py b/src/structify/types/chat_session_with_messages.py index 42a4f3ec3..7820f2e7c 100644 --- a/src/structify/types/chat_session_with_messages.py +++ b/src/structify/types/chat_session_with_messages.py @@ -43,7 +43,7 @@ class Message(BaseModel): content_proto: Optional[object] = None - git_commit_id: Optional[str] = None + git_hash: Optional[str] = None previous_message_id: Optional[str] = None @@ -69,6 +69,8 @@ class ChatSessionWithMessages(BaseModel): created_at: datetime + ephemeral: bool + git_application_token: str is_favorite: bool @@ -87,8 +89,12 @@ class ChatSessionWithMessages(BaseModel): visibility: ChatVisibility + instantiated_from_template_id: Optional[str] = None + latest_workflow_session_id: Optional[str] = None + message_head: Optional[str] = None + name: Optional[str] = None project_id: Optional[str] = None diff --git a/src/structify/types/chat_simulate_prompt_params.py b/src/structify/types/chat_simulate_prompt_params.py new file mode 100644 index 000000000..c9a3df372 --- /dev/null +++ b/src/structify/types/chat_simulate_prompt_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .chat_prompt_param import ChatPromptParam + +__all__ = ["ChatSimulatePromptParams"] + + +class ChatSimulatePromptParams(TypedDict, total=False): + chat_prompt: Required[ChatPromptParam] diff --git a/src/structify/types/chat_template.py b/src/structify/types/chat_template.py index c7c96474d..1c93c1eab 100644 --- a/src/structify/types/chat_template.py +++ b/src/structify/types/chat_template.py @@ -1,8 +1,10 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List from datetime import datetime from .._models import BaseModel +from .template_question import TemplateQuestion __all__ = ["ChatTemplate"] @@ -24,6 +26,8 @@ class ChatTemplate(BaseModel): is_active: bool + questions: List[TemplateQuestion] + title: str updated_at: datetime diff --git a/src/structify/types/chat_update_session_params.py b/src/structify/types/chat_update_session_params.py index e3ac063cb..b7f62a070 100644 --- a/src/structify/types/chat_update_session_params.py +++ b/src/structify/types/chat_update_session_params.py @@ -9,6 +9,8 @@ class ChatUpdateSessionParams(TypedDict, total=False): + message_head: Optional[str] + name: Optional[str] project_id: Optional[str] diff --git a/src/structify/types/chat_upload_input_file_params.py b/src/structify/types/chat_upload_input_file_params.py new file mode 100644 index 000000000..a4a6eb732 --- /dev/null +++ b/src/structify/types/chat_upload_input_file_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .._types import FileTypes + +__all__ = ["ChatUploadInputFileParams"] + + +class ChatUploadInputFileParams(TypedDict, total=False): + content: Required[FileTypes] + + content_type: Required[str] + + file_name: Required[str] diff --git a/src/structify/types/chat_upload_input_file_response.py b/src/structify/types/chat_upload_input_file_response.py new file mode 100644 index 000000000..29e08729c --- /dev/null +++ b/src/structify/types/chat_upload_input_file_response.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["ChatUploadInputFileResponse", "File"] + + +class File(BaseModel): + chat_session_id: str + + content_type: str + + created_at: datetime + + file_size: int + + filename: str + + +class ChatUploadInputFileResponse(BaseModel): + file: File diff --git a/src/structify/types/chat_visibility.py b/src/structify/types/chat_visibility.py index 562a18934..d53c3721a 100644 --- a/src/structify/types/chat_visibility.py +++ b/src/structify/types/chat_visibility.py @@ -4,4 +4,4 @@ __all__ = ["ChatVisibility"] -ChatVisibility: TypeAlias = Literal["private", "shared_with_team", "public"] +ChatVisibility: TypeAlias = Literal["private", "shared_with_team", "shared_with_team_view", "public"] diff --git a/src/structify/types/code_apply_manual_edit_params.py b/src/structify/types/code_apply_manual_edit_params.py new file mode 100644 index 000000000..ba00c6880 --- /dev/null +++ b/src/structify/types/code_apply_manual_edit_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CodeApplyManualEditParams"] + + +class CodeApplyManualEditParams(TypedDict, total=False): + code: Required[str] + + filename: Required[str] diff --git a/src/structify/types/code_generate_code_params.py b/src/structify/types/code_generate_code_params.py index c93a743bc..0d8de217d 100644 --- a/src/structify/types/code_generate_code_params.py +++ b/src/structify/types/code_generate_code_params.py @@ -61,7 +61,9 @@ class Config(TypedDict, total=False): "gemini.gemini-2.5-flash", "gemini.gemini-3-pro-preview", "gemini.gemini-3-flash-preview", + "gemini.gemini-3.1-flash-lite-preview", "vertex_anthropic.claude-sonnet-4-5-vertex", + "vertex_anthropic.claude-opus-4-5-vertex", ] ] """LLM model keys available in the system. Format: .""" diff --git a/src/structify/types/compress_chat_response.py b/src/structify/types/compress_chat_response.py new file mode 100644 index 000000000..17433aa85 --- /dev/null +++ b/src/structify/types/compress_chat_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["CompressChatResponse"] + + +class CompressChatResponse(BaseModel): + status: str diff --git a/src/structify/types/connector.py b/src/structify/types/connector.py index d40f64e70..fb8393c35 100644 --- a/src/structify/types/connector.py +++ b/src/structify/types/connector.py @@ -1,11 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel from .connector_category import ConnectorCategory -from .exploration_status import ExplorationStatus +from .datahub_secret_map import DatahubSecretMap __all__ = ["Connector"] @@ -15,36 +16,40 @@ class Connector(BaseModel): created_at: datetime - exploration_status: ExplorationStatus - known_connector_type: str name: str + owner_user_id: str + team_id: str + team_visibility: Literal["Team", "Private"] + updated_at: datetime connector_category: Optional[ConnectorCategory] = None + datahub_ingestion_type: Optional[str] = None + + datahub_secret_map: Optional[DatahubSecretMap] = None + """ + Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + """ + datahub_urn: Optional[str] = None deleted_at: Optional[datetime] = None description: Optional[str] = None - exploration_error: Optional[str] = None - - exploration_started_at: Optional[datetime] = None - nango_connection_id: Optional[str] = None - nango_integration_id: Optional[str] = None - - pipedream_account_id: Optional[str] = None + oauth_scopes: Optional[List[Optional[str]]] = None - pipedream_external_id: Optional[str] = None + refresh_cron_schedule: Optional[str] = None - refresh_script: Optional[str] = None + refresh_next_run_at: Optional[datetime] = None usage_snippet_override: Optional[str] = None diff --git a/src/structify/types/connector_catalog/admin_create_catalog_params.py b/src/structify/types/connector_catalog/admin_create_catalog_params.py index 3662fcbec..98662c009 100644 --- a/src/structify/types/connector_catalog/admin_create_catalog_params.py +++ b/src/structify/types/connector_catalog/admin_create_catalog_params.py @@ -19,4 +19,8 @@ class AdminCreateCatalogParams(TypedDict, total=False): description: Optional[str] + enterprise_only: bool + + onboarding_priority: Optional[int] + priority: Optional[int] diff --git a/src/structify/types/connector_catalog/admin_update_catalog_params.py b/src/structify/types/connector_catalog/admin_update_catalog_params.py index 90f8b2286..23d639c71 100644 --- a/src/structify/types/connector_catalog/admin_update_catalog_params.py +++ b/src/structify/types/connector_catalog/admin_update_catalog_params.py @@ -15,6 +15,10 @@ class AdminUpdateCatalogParams(TypedDict, total=False): description: Optional[str] + enterprise_only: Optional[bool] + name: Optional[str] + onboarding_priority: Optional[int] + priority: Optional[int] diff --git a/src/structify/types/connector_catalog/connector_catalog.py b/src/structify/types/connector_catalog/connector_catalog.py index c68249b73..8f0b9eb5e 100644 --- a/src/structify/types/connector_catalog/connector_catalog.py +++ b/src/structify/types/connector_catalog/connector_catalog.py @@ -15,6 +15,8 @@ class ConnectorCatalog(BaseModel): created_at: datetime + enterprise_only: bool + name: str slug: str @@ -23,4 +25,6 @@ class ConnectorCatalog(BaseModel): description: Optional[str] = None + onboarding_priority: Optional[int] = None + priority: Optional[int] = None diff --git a/src/structify/types/connector_catalog_list_params.py b/src/structify/types/connector_catalog_list_params.py index 7189a9672..3ccf7f44e 100644 --- a/src/structify/types/connector_catalog_list_params.py +++ b/src/structify/types/connector_catalog_list_params.py @@ -5,10 +5,18 @@ from typing import Optional from typing_extensions import TypedDict +from .._types import SequenceNotStr + __all__ = ["ConnectorCatalogListParams"] class ConnectorCatalogListParams(TypedDict, total=False): + categories: SequenceNotStr[str] + """ + Optional category filter (exact match against any element in the categories + array) + """ + include_inactive: bool """Include inactive auth methods (admin only)""" diff --git a/src/structify/types/connector_create_params.py b/src/structify/types/connector_create_params.py index 1f5534267..1195618b6 100644 --- a/src/structify/types/connector_create_params.py +++ b/src/structify/types/connector_create_params.py @@ -13,24 +13,10 @@ class ConnectorCreateParams(TypedDict, total=False): name: Required[str] - team_id: Required[str] - description: Optional[str] nango_connection_id: Optional[str] """Nango connection ID for OAuth token management""" - nango_integration_id: Optional[str] - """Nango integration ID (e.g., "linear", "slack")""" - - pipedream_account_id: Optional[str] - - pipedream_external_id: Optional[str] - """Unique external ID for Pipedream routing (required for Pipedream connectors)""" - - pipedream_project_id: Optional[str] - - refresh_script: Optional[str] - secrets: Dict[str, str] """Optional secrets/environment variables for the connector""" diff --git a/src/structify/types/connector_download_datahub_artifact_params.py b/src/structify/types/connector_download_datahub_artifact_params.py new file mode 100644 index 000000000..d62b879dd --- /dev/null +++ b/src/structify/types/connector_download_datahub_artifact_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +__all__ = ["ConnectorDownloadDatahubArtifactParams"] + + +class ConnectorDownloadDatahubArtifactParams(TypedDict, total=False): + connector_id: Required[str] + + exploration_run_id: Optional[str] diff --git a/src/structify/types/connector_explore_params.py b/src/structify/types/connector_explore_params.py index d4b23d4b9..4d94d5501 100644 --- a/src/structify/types/connector_explore_params.py +++ b/src/structify/types/connector_explore_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, TypedDict +from typing_extensions import TypedDict __all__ = ["ConnectorExploreParams"] @@ -11,9 +11,9 @@ class ConnectorExploreParams(TypedDict, total=False): database_id: Optional[str] - schema_id: Optional[str] + only_do_datahub: Optional[bool] + """If true, run only DataHub ingestion without queuing Diego annotation jobs.""" - stage: Optional[Literal["both", "ingestion", "annotation"]] - """Which exploration stage to run""" + schema_id: Optional[str] table_id: Optional[str] diff --git a/src/structify/types/connector_explore_response.py b/src/structify/types/connector_explore_response.py new file mode 100644 index 000000000..f6dbedfce --- /dev/null +++ b/src/structify/types/connector_explore_response.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ConnectorExploreResponse"] + + +class ConnectorExploreResponse(BaseModel): + id: str + + created_at: datetime + + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] + + max_steps_without_save: int + + membership_id: str + + status: Literal["Queued", "Running", "Completed", "Failed"] + + updated_at: datetime + + use_proxy: bool + + user_id: str + + dataset_id: Optional[str] = None + + exploration_run_id: Optional[str] = None + + max_errors: Optional[int] = None + + max_execution_time_secs: Optional[int] = None + + max_total_steps: Optional[int] = None + + message: Optional[str] = None + """A message about the status of the job at completion""" + + node_id: Optional[str] = None + + parameters: Optional[object] = None + """Proto for JobInput""" + + reason: Optional[str] = None + """A reason for the job's existence""" + + run_started_time: Optional[datetime] = None + """What time did the job start running?""" + + run_time_milliseconds: Optional[int] = None + + seeded_kg_search_term: Optional[str] = None diff --git a/src/structify/types/connector_get_explorer_chat_params.py b/src/structify/types/connector_get_explorer_chat_params.py index f84ede929..32d136fc4 100644 --- a/src/structify/types/connector_get_explorer_chat_params.py +++ b/src/structify/types/connector_get_explorer_chat_params.py @@ -2,11 +2,17 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Optional +from typing_extensions import TypedDict __all__ = ["ConnectorGetExplorerChatParams"] class ConnectorGetExplorerChatParams(TypedDict, total=False): - run_id: Required[str] - """Exploration run ID (required)""" + database_id: Optional[str] + + run_id: Optional[str] + + schema_id: Optional[str] + + table_id: Optional[str] diff --git a/src/structify/types/connector_get_response.py b/src/structify/types/connector_get_response.py index f1ec3ee59..c566b553e 100644 --- a/src/structify/types/connector_get_response.py +++ b/src/structify/types/connector_get_response.py @@ -23,3 +23,5 @@ class ConnectorGetResponseSecret(BaseModel): class ConnectorGetResponse(Connector): secrets: List[ConnectorGetResponseSecret] + + shared_user_ids: List[str] diff --git a/src/structify/types/connector_list_params.py b/src/structify/types/connector_list_params.py index 6f9c91258..7be465a02 100644 --- a/src/structify/types/connector_list_params.py +++ b/src/structify/types/connector_list_params.py @@ -2,15 +2,12 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict __all__ = ["ConnectorListParams"] class ConnectorListParams(TypedDict, total=False): - team_id: Required[str] - """Team ID to list connectors for""" - limit: int offset: int diff --git a/src/structify/types/connector_list_stores_response.py b/src/structify/types/connector_list_stores_response.py new file mode 100644 index 000000000..f2675f159 --- /dev/null +++ b/src/structify/types/connector_list_stores_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +from .llm_information_store import LlmInformationStore + +__all__ = ["ConnectorListStoresResponse"] + +ConnectorListStoresResponse: TypeAlias = Dict[str, LlmInformationStore] diff --git a/src/structify/types/connector_list_with_snippets_params.py b/src/structify/types/connector_list_with_snippets_params.py deleted file mode 100644 index 998cd2f6b..000000000 --- a/src/structify/types/connector_list_with_snippets_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ConnectorListWithSnippetsParams"] - - -class ConnectorListWithSnippetsParams(TypedDict, total=False): - team_id: Required[str] - """Team ID to list connectors for""" diff --git a/src/structify/types/connector_search_tables_params.py b/src/structify/types/connector_search_tables_params.py index 2f2847016..83b002eec 100644 --- a/src/structify/types/connector_search_tables_params.py +++ b/src/structify/types/connector_search_tables_params.py @@ -12,4 +12,4 @@ class ConnectorSearchTablesParams(TypedDict, total=False): """Search query string""" team_id: Required[str] - """Team ID to search tables for""" + """Team ID to scope table search""" diff --git a/src/structify/types/connector_search_tables_response.py b/src/structify/types/connector_search_tables_response.py index bbf3314a5..ef591a4ac 100644 --- a/src/structify/types/connector_search_tables_response.py +++ b/src/structify/types/connector_search_tables_response.py @@ -21,6 +21,8 @@ class RankedResultColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" @@ -34,6 +36,8 @@ class RankedResultColumn(BaseModel): class RankedResultTableColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" @@ -84,6 +88,8 @@ class RankedResult(BaseModel): class RawResultColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" @@ -97,6 +103,8 @@ class RawResultColumn(BaseModel): class RawResultTableColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" diff --git a/src/structify/types/connector_summaries_params.py b/src/structify/types/connector_summaries_params.py index 886dfcca3..46632c7f3 100644 --- a/src/structify/types/connector_summaries_params.py +++ b/src/structify/types/connector_summaries_params.py @@ -11,5 +11,3 @@ class ConnectorSummariesParams(TypedDict, total=False): connector_ids: Required[SequenceNotStr[str]] - - team_id: Required[str] diff --git a/src/structify/types/connector_table_path_response.py b/src/structify/types/connector_table_path_response.py new file mode 100644 index 000000000..973e2493a --- /dev/null +++ b/src/structify/types/connector_table_path_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["ConnectorTablePathResponse"] + + +class ConnectorTablePathResponse(BaseModel): + connector_id: str + + database_name: str + + schema_name: str + + table_name: str diff --git a/src/structify/types/connector_update_params.py b/src/structify/types/connector_update_params.py index 51ffbed78..9b1a14456 100644 --- a/src/structify/types/connector_update_params.py +++ b/src/structify/types/connector_update_params.py @@ -3,18 +3,44 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +from typing_extensions import Literal, TypedDict + +from .._types import SequenceNotStr +from .connector_category import ConnectorCategory +from .datahub_secret_map_param import DatahubSecretMapParam __all__ = ["ConnectorUpdateParams"] class ConnectorUpdateParams(TypedDict, total=False): + connector_category: Optional[ConnectorCategory] + + datahub_ingestion_type: Optional[str] + + datahub_secret_map: Optional[DatahubSecretMapParam] + """ + Maps DatahubIngestionKey to the name of the connector secret that holds the + value. + """ + + datahub_urn: Optional[str] + description: Optional[str] known_connector_type: Optional[str] name: Optional[str] - refresh_script: Optional[str] + nango_connection_id: Optional[str] + + oauth_scopes: Optional[SequenceNotStr[Optional[str]]] + + owner_user_id: Optional[str] + + refresh_cron_schedule: Optional[str] + + team_visibility: Optional[Literal["Team", "Private"]] usage_snippet_override: Optional[str] + + user_ids: Optional[SequenceNotStr[str]] diff --git a/src/structify/types/connector_upload_datahub_artifact_params.py b/src/structify/types/connector_upload_datahub_artifact_params.py new file mode 100644 index 000000000..d7e22d8f5 --- /dev/null +++ b/src/structify/types/connector_upload_datahub_artifact_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .._types import FileTypes + +__all__ = ["ConnectorUploadDatahubArtifactParams"] + + +class ConnectorUploadDatahubArtifactParams(TypedDict, total=False): + connector_id: Required[str] + + exploration_run_id: Required[str] + + file: Required[FileTypes] diff --git a/src/structify/types/connector_with_secrets.py b/src/structify/types/connector_with_secrets.py index 6f471b74d..0e8a26b76 100644 --- a/src/structify/types/connector_with_secrets.py +++ b/src/structify/types/connector_with_secrets.py @@ -12,8 +12,6 @@ class ConnectorWithSecretsSecret(BaseModel): """Response model for listing secrets (without sensitive data)""" - id: str - created_at: datetime secret_name: str diff --git a/src/structify/types/dashboard_item.py b/src/structify/types/dashboard_item.py new file mode 100644 index 000000000..586b4755c --- /dev/null +++ b/src/structify/types/dashboard_item.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .dashboard_spec import DashboardSpec + +__all__ = ["DashboardItem"] + + +class DashboardItem(BaseModel): + file_name: str + """File path relative to repository root.""" + + spec: DashboardSpec diff --git a/src/structify/types/dashboard_spec.py b/src/structify/types/dashboard_spec.py new file mode 100644 index 000000000..5bc8dbc38 --- /dev/null +++ b/src/structify/types/dashboard_spec.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List + +from .._models import BaseModel +from .viz_param import VizParam +from .viz_query import VizQuery +from .viz_figure import VizFigure + +__all__ = ["DashboardSpec"] + + +class DashboardSpec(BaseModel): + dataset: str + + description: str + + figures: List[VizFigure] + + params: Dict[str, VizParam] + + queries: List[VizQuery] + + title: str + + version: str diff --git a/src/structify/types/dashboard_spec_param.py b/src/structify/types/dashboard_spec_param.py new file mode 100644 index 000000000..baa9907f6 --- /dev/null +++ b/src/structify/types/dashboard_spec_param.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Iterable +from typing_extensions import Required, TypedDict + +from .viz_param_param import VizParamParam +from .viz_query_param import VizQueryParam +from .viz_figure_param import VizFigureParam + +__all__ = ["DashboardSpecParam"] + + +class DashboardSpecParam(TypedDict, total=False): + dataset: Required[str] + + description: Required[str] + + figures: Required[Iterable[VizFigureParam]] + + params: Required[Dict[str, VizParamParam]] + + queries: Required[Iterable[VizQueryParam]] + + title: Required[str] + + version: Required[str] diff --git a/src/structify/types/datahub_progress.py b/src/structify/types/datahub_progress.py new file mode 100644 index 000000000..5fd316fa6 --- /dev/null +++ b/src/structify/types/datahub_progress.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DatahubProgress"] + + +class DatahubProgress(BaseModel): + databases_created: int + + job_id: str + + job_status: Literal["Queued", "Running", "Completed", "Failed"] + + pages_fetched: int + + records_written: int + + schemas_created: int + + tables_processed: int + + total_datasets: int diff --git a/src/structify/types/datahub_secret_map.py b/src/structify/types/datahub_secret_map.py new file mode 100644 index 000000000..bf80a823b --- /dev/null +++ b/src/structify/types/datahub_secret_map.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["DatahubSecretMap"] + +DatahubSecretMap: TypeAlias = Dict[str, str] diff --git a/src/structify/types/datahub_secret_map_param.py b/src/structify/types/datahub_secret_map_param.py new file mode 100644 index 000000000..6cd1d2874 --- /dev/null +++ b/src/structify/types/datahub_secret_map_param.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["DatahubSecretMapParam"] + +DatahubSecretMapParam: TypeAlias = Dict[str, str] diff --git a/src/structify/types/dataset_view_table_response.py b/src/structify/types/dataset_view_table_response.py index 2080355a2..18e546830 100644 --- a/src/structify/types/dataset_view_table_response.py +++ b/src/structify/types/dataset_view_table_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from datetime import datetime from typing_extensions import Literal, TypeAlias @@ -103,10 +103,10 @@ class DatasetViewTableResponse(BaseModel): dataset_id: str - job_ids: List[str] - label: str properties: Dict[str, Properties] updated_at: datetime + + job_id: Optional[str] = None diff --git a/src/structify/types/dataset_view_tables_with_relationships_response.py b/src/structify/types/dataset_view_tables_with_relationships_response.py index 2dbf55099..72ecfb24f 100644 --- a/src/structify/types/dataset_view_tables_with_relationships_response.py +++ b/src/structify/types/dataset_view_tables_with_relationships_response.py @@ -118,14 +118,14 @@ class ConnectedEntity(BaseModel): dataset_id: str - job_ids: List[str] - label: str properties: Dict[str, ConnectedEntityProperties] updated_at: datetime + job_id: Optional[str] = None + class EntityPropertiesPartialDateObject(BaseModel): original_string: str @@ -212,14 +212,14 @@ class Entity(BaseModel): dataset_id: str - job_ids: List[str] - label: str properties: Dict[str, EntityProperties] updated_at: datetime + job_id: Optional[str] = None + class RelationshipPropertiesPartialDateObject(BaseModel): original_string: str diff --git a/src/structify/types/entity_get_local_subgraph_response.py b/src/structify/types/entity_get_local_subgraph_response.py index e3ed1bcb7..eeb9e4348 100644 --- a/src/structify/types/entity_get_local_subgraph_response.py +++ b/src/structify/types/entity_get_local_subgraph_response.py @@ -117,6 +117,8 @@ class Neighbor(BaseModel): updated_at: datetime + job_id: Optional[str] = None + class RelationshipPropertiesPartialDateObject(BaseModel): original_string: str diff --git a/src/structify/types/entity_get_response.py b/src/structify/types/entity_get_response.py index fb913d686..43e98a9a2 100644 --- a/src/structify/types/entity_get_response.py +++ b/src/structify/types/entity_get_response.py @@ -108,3 +108,5 @@ class EntityGetResponse(BaseModel): properties: Dict[str, Properties] updated_at: datetime + + job_id: Optional[str] = None diff --git a/src/structify/types/entity_list_jobs_response.py b/src/structify/types/entity_list_jobs_response.py index 1bcedcda2..85ddcb6dc 100644 --- a/src/structify/types/entity_list_jobs_response.py +++ b/src/structify/types/entity_list_jobs_response.py @@ -14,9 +14,7 @@ class EntityListJobsResponseItem(BaseModel): created_at: datetime - dataset_id: str - - job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"] + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] max_steps_without_save: int @@ -30,6 +28,10 @@ class EntityListJobsResponseItem(BaseModel): user_id: str + dataset_id: Optional[str] = None + + exploration_run_id: Optional[str] = None + max_errors: Optional[int] = None max_execution_time_secs: Optional[int] = None diff --git a/src/structify/types/entity_search_response.py b/src/structify/types/entity_search_response.py index 5edf5eca8..ef9e15d45 100644 --- a/src/structify/types/entity_search_response.py +++ b/src/structify/types/entity_search_response.py @@ -110,5 +110,7 @@ class EntitySearchResponseItem(BaseModel): updated_at: datetime + job_id: Optional[str] = None + EntitySearchResponse: TypeAlias = List[EntitySearchResponseItem] diff --git a/src/structify/types/entity_summarize_response.py b/src/structify/types/entity_summarize_response.py index c1eecbfde..7ce3c6dde 100644 --- a/src/structify/types/entity_summarize_response.py +++ b/src/structify/types/entity_summarize_response.py @@ -110,5 +110,7 @@ class EntitySummarizeResponseItem(BaseModel): updated_at: datetime + job_id: Optional[str] = None + EntitySummarizeResponse: TypeAlias = List[EntitySummarizeResponseItem] diff --git a/src/structify/types/entity_update_property_response.py b/src/structify/types/entity_update_property_response.py index 9d0e10065..015a19568 100644 --- a/src/structify/types/entity_update_property_response.py +++ b/src/structify/types/entity_update_property_response.py @@ -108,3 +108,5 @@ class EntityUpdatePropertyResponse(BaseModel): properties: Dict[str, Properties] updated_at: datetime + + job_id: Optional[str] = None diff --git a/src/structify/types/entity_view_response.py b/src/structify/types/entity_view_response.py index d66212f6f..7bba540f1 100644 --- a/src/structify/types/entity_view_response.py +++ b/src/structify/types/entity_view_response.py @@ -142,6 +142,8 @@ class ConnectedEntity(BaseModel): updated_at: datetime + job_id: Optional[str] = None + class EntityPropertiesPartialDateObject(BaseModel): original_string: str @@ -234,6 +236,8 @@ class Entity(BaseModel): updated_at: datetime + job_id: Optional[str] = None + class RelationshipPropertiesPartialDateObject(BaseModel): original_string: str @@ -422,6 +426,8 @@ class SimilarEntity(BaseModel): updated_at: datetime + job_id: Optional[str] = None + class SourceLocationTextText(BaseModel): byte_offset: int diff --git a/src/structify/types/exploration_progress.py b/src/structify/types/exploration_progress.py new file mode 100644 index 000000000..2b3d4f515 --- /dev/null +++ b/src/structify/types/exploration_progress.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .phase_activity import PhaseActivity +from .datahub_progress import DatahubProgress + +__all__ = ["ExplorationProgress"] + + +class ExplorationProgress(BaseModel): + phases: List[PhaseActivity] + + datahub: Optional[DatahubProgress] = None diff --git a/src/structify/types/exploration_run.py b/src/structify/types/exploration_run.py index ff4368f5a..e4bb3798a 100644 --- a/src/structify/types/exploration_run.py +++ b/src/structify/types/exploration_run.py @@ -1,13 +1,25 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from datetime import datetime from .._models import BaseModel +from .exploration_status import ExplorationStatus __all__ = ["ExplorationRun"] class ExplorationRun(BaseModel): + id: str + + connector_id: str + created_at: datetime - run_id: str + status: ExplorationStatus + + checkpoint_blob_name: Optional[str] = None + + latest_snapshot_blob_name: Optional[str] = None + + triggered_by: Optional[str] = None diff --git a/src/structify/types/explore_status_response.py b/src/structify/types/explore_status_response.py deleted file mode 100644 index 475324a99..000000000 --- a/src/structify/types/explore_status_response.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from .._models import BaseModel -from .exploration_status import ExplorationStatus - -__all__ = ["ExploreStatusResponse"] - - -class ExploreStatusResponse(BaseModel): - status: ExplorationStatus - - error: Optional[str] = None - - started_at: Optional[datetime] = None diff --git a/src/structify/types/get_chat_session_response.py b/src/structify/types/get_chat_session_response.py index 5ad205a0d..3a31d94ed 100644 --- a/src/structify/types/get_chat_session_response.py +++ b/src/structify/types/get_chat_session_response.py @@ -7,6 +7,7 @@ from .._models import BaseModel from .chat_event import ChatEvent from .chat_visibility import ChatVisibility +from .workflow_session import WorkflowSession from .chat_session_role import ChatSessionRole __all__ = ["GetChatSessionResponse", "Session", "SessionCommit", "SessionMessage"] @@ -37,6 +38,10 @@ class SessionMessage(BaseModel): timestamp: datetime + git_hash: Optional[str] = None + + previous_message_id: Optional[str] = None + class Session(BaseModel): id: str @@ -45,6 +50,8 @@ class Session(BaseModel): created_at: datetime + ephemeral: bool + git_application_token: str is_favorite: bool @@ -63,8 +70,14 @@ class Session(BaseModel): visibility: ChatVisibility + workflow_sessions: List[WorkflowSession] + + instantiated_from_template_id: Optional[str] = None + latest_workflow_session_id: Optional[str] = None + message_head: Optional[str] = None + name: Optional[str] = None project_id: Optional[str] = None diff --git a/src/structify/types/get_onboarding_answers_response.py b/src/structify/types/get_onboarding_answers_response.py new file mode 100644 index 000000000..cada36acc --- /dev/null +++ b/src/structify/types/get_onboarding_answers_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .onboarding_answers import OnboardingAnswers + +__all__ = ["GetOnboardingAnswersResponse"] + + +class GetOnboardingAnswersResponse(BaseModel): + answers: OnboardingAnswers diff --git a/src/structify/types/job_cancel_response.py b/src/structify/types/job_cancel_response.py index 640fcf079..01f4a4293 100644 --- a/src/structify/types/job_cancel_response.py +++ b/src/structify/types/job_cancel_response.py @@ -14,9 +14,7 @@ class JobCancelResponse(BaseModel): created_at: datetime - dataset_id: str - - job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"] + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] max_steps_without_save: int @@ -30,6 +28,10 @@ class JobCancelResponse(BaseModel): user_id: str + dataset_id: Optional[str] = None + + exploration_run_id: Optional[str] = None + max_errors: Optional[int] = None max_execution_time_secs: Optional[int] = None diff --git a/src/structify/types/job_event_body.py b/src/structify/types/job_event_body.py index 85f1e3f9f..d35bb49af 100644 --- a/src/structify/types/job_event_body.py +++ b/src/structify/types/job_event_body.py @@ -24,6 +24,8 @@ "DatahubDatabasesCreated", "DatahubSchemasCreated", "DatahubTablesProcessed", + "DatahubAnnotationsQueued", + "DatahubIngestionProgress", "DatahubEmbeddingBatch", "ViewedPdfPage", ] @@ -167,9 +169,25 @@ class DatahubTablesProcessed(BaseModel): tables_failed: int + tables_removed: int + tables_updated: int +class DatahubAnnotationsQueued(BaseModel): + diff_annotations_queued: int + + event_type: Literal["datahub_annotations_queued"] + + full_annotations_queued: int + + +class DatahubIngestionProgress(BaseModel): + event_type: Literal["datahub_ingestion_progress"] + + records_written: int + + class DatahubEmbeddingBatch(BaseModel): batch_num: int @@ -203,6 +221,8 @@ class ViewedPdfPage(BaseModel): DatahubDatabasesCreated, DatahubSchemasCreated, DatahubTablesProcessed, + DatahubAnnotationsQueued, + DatahubIngestionProgress, DatahubEmbeddingBatch, ViewedPdfPage, ], diff --git a/src/structify/types/job_get_response.py b/src/structify/types/job_get_response.py new file mode 100644 index 000000000..82961dcbf --- /dev/null +++ b/src/structify/types/job_get_response.py @@ -0,0 +1,368 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from pydantic import Field as FieldInfo + +from .image import Image +from .source import Source +from .._models import BaseModel +from .chat_event import ChatEvent +from .chat_prompt import ChatPrompt +from .knowledge_graph import KnowledgeGraph +from .save_requirement import SaveRequirement +from .exploration_phase_id import ExplorationPhaseID + +__all__ = [ + "JobGetResponse", + "Agent", + "Info", + "InfoParameters", + "InfoParametersStructuringInput", + "InfoParametersStructuringInputAgent", + "InfoParametersStructuringInputAgentAgent", + "InfoParametersStructuringInputAgentAgentPdf", + "InfoParametersStructuringInputAgentAgentPdfPdf", + "InfoParametersStructuringInputAgentAgentWeb", + "InfoParametersStructuringInputAgentAgentWebWeb", + "InfoParametersStructuringInputTransformationPrompt", + "InfoParametersStructuringInputScrapeFromURLProperty", + "InfoParametersStructuringInputScrapeFromURLPropertyScrapeFromURLProperty", + "InfoParametersStructuringInputScrapeURL", + "InfoParametersStructuringInputScrapeURLScrapeURL", + "InfoParametersStructuringInputDatahubIngestion", + "InfoParametersStructuringInputDatahubIngestionDatahubIngestion", + "InfoParametersStructuringInputConnectorExploration", + "InfoParametersStructuringInputConnectorExplorationConnectorExploration", + "Saved", + "SavedProperties", + "SavedPropertiesPartialDateObject", + "SavedPropertiesURLObject", + "SavedPropertiesMoneyObject", + "SavedPropertiesPersonName", + "SavedPropertiesAddressObject", + "SavedLocation", + "SavedLocationText", + "SavedLocationTextText", + "SavedLocationVisual", + "SavedLocationVisualVisual", + "SavedLocationPage", + "SavedLocationPagePage", +] + + +class Agent(BaseModel): + base_url: str + + is_newly_created: bool + + scraper_created_at: datetime + + scraper_id: str + + scraper_updated_at: datetime + + chat: Optional[ChatPrompt] = None + + code: Optional[str] = None + + events: Optional[List[ChatEvent]] = None + + next_page_code: Optional[str] = None + + +class InfoParametersStructuringInputAgentAgentPdfPdf(BaseModel): + """Ingest all pages of a PDF and process them independently.""" + + path: str + + page: Optional[int] = None + + +class InfoParametersStructuringInputAgentAgentPdf(BaseModel): + pdf: InfoParametersStructuringInputAgentAgentPdfPdf = FieldInfo(alias="PDF") + """Ingest all pages of a PDF and process them independently.""" + + +class InfoParametersStructuringInputAgentAgentWebWeb(BaseModel): + banned_domains: Optional[List[str]] = None + + starting_searches: Optional[List[str]] = None + + starting_urls: Optional[List[str]] = None + + +class InfoParametersStructuringInputAgentAgentWeb(BaseModel): + web: InfoParametersStructuringInputAgentAgentWebWeb = FieldInfo(alias="Web") + + +InfoParametersStructuringInputAgentAgent: TypeAlias = Union[ + InfoParametersStructuringInputAgentAgentPdf, InfoParametersStructuringInputAgentAgentWeb +] + + +class InfoParametersStructuringInputAgent(BaseModel): + agent: InfoParametersStructuringInputAgentAgent = FieldInfo(alias="Agent") + + +class InfoParametersStructuringInputTransformationPrompt(BaseModel): + transformation_prompt: str = FieldInfo(alias="TransformationPrompt") + + +class InfoParametersStructuringInputScrapeFromURLPropertyScrapeFromURLProperty(BaseModel): + batch_scrape: bool + + url_property_name: str + + use_markdown: bool + + +class InfoParametersStructuringInputScrapeFromURLProperty(BaseModel): + scrape_from_url_property: InfoParametersStructuringInputScrapeFromURLPropertyScrapeFromURLProperty = FieldInfo( + alias="ScrapeFromUrlProperty" + ) + + +class InfoParametersStructuringInputScrapeURLScrapeURL(BaseModel): + batch_scrape: bool + + url: str + + use_markdown: bool + + +class InfoParametersStructuringInputScrapeURL(BaseModel): + scrape_url: InfoParametersStructuringInputScrapeURLScrapeURL = FieldInfo(alias="ScrapeUrl") + + +class InfoParametersStructuringInputDatahubIngestionDatahubIngestion(BaseModel): + connector_id: str + + exploration_run_id: str + + only_do_datahub: bool + + +class InfoParametersStructuringInputDatahubIngestion(BaseModel): + datahub_ingestion: InfoParametersStructuringInputDatahubIngestionDatahubIngestion = FieldInfo( + alias="DatahubIngestion" + ) + + +class InfoParametersStructuringInputConnectorExplorationConnectorExploration(BaseModel): + connector_id: str + + exploration_phase_id: ExplorationPhaseID + """Identifies the phase of connector exploration + + This enum is used to track which phase of exploration a chat session belongs to. + It's stored as JSONB in the database to allow for flexible phase identification. + """ + + exploration_run_id: str + + strategy: Literal["full", "diff"] + + +class InfoParametersStructuringInputConnectorExploration(BaseModel): + connector_exploration: InfoParametersStructuringInputConnectorExplorationConnectorExploration = FieldInfo( + alias="ConnectorExploration" + ) + + +InfoParametersStructuringInput: TypeAlias = Union[ + InfoParametersStructuringInputAgent, + InfoParametersStructuringInputTransformationPrompt, + InfoParametersStructuringInputScrapeFromURLProperty, + InfoParametersStructuringInputScrapeURL, + InfoParametersStructuringInputDatahubIngestion, + InfoParametersStructuringInputConnectorExploration, +] + + +class InfoParameters(BaseModel): + allow_extra_entities: bool + + extraction_criteria: List[SaveRequirement] + + structuring_input: InfoParametersStructuringInput + + instructions: Optional[str] = None + + model: Optional[str] = None + + seeded_kg: Optional[KnowledgeGraph] = None + """ + Knowledge graph info structured to deserialize and display in the same format + that the LLM outputs. Also the first representation of an LLM output in the + pipeline from raw tool output to being merged into a DB + """ + + +class Info(BaseModel): + id: str + + created_at: datetime + + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] + + status: Literal["Queued", "Running", "Completed", "Failed"] + + user_id: str + + dataset_id: Optional[str] = None + + message: Optional[str] = None + + parameters: Optional[InfoParameters] = None + + reason: Optional[str] = None + + run_started_time: Optional[datetime] = None + + run_time_milliseconds: Optional[int] = None + + +class SavedPropertiesPartialDateObject(BaseModel): + original_string: str + + year: int + + day: Optional[int] = None + + month: Optional[int] = None + + +class SavedPropertiesURLObject(BaseModel): + original_string: str + + url: str + + +class SavedPropertiesMoneyObject(BaseModel): + amount: float + + currency_code: Literal[ + "USD", + "EUR", + "GBP", + "JPY", + "CNY", + "INR", + "RUB", + "CAD", + "AUD", + "CHF", + "ILS", + "NZD", + "SGD", + "HKD", + "NOK", + "SEK", + "PLN", + "TRY", + "DKK", + "MXN", + "ZAR", + "PHP", + "VND", + "THB", + "BRL", + "KRW", + ] + + original_string: str + + +class SavedPropertiesPersonName(BaseModel): + name: str + + +class SavedPropertiesAddressObject(BaseModel): + components: Dict[str, str] + + original_address: str + + +SavedProperties: TypeAlias = Union[ + str, + bool, + float, + SavedPropertiesPartialDateObject, + str, + str, + SavedPropertiesURLObject, + str, + SavedPropertiesMoneyObject, + Image, + SavedPropertiesPersonName, + SavedPropertiesAddressObject, + str, +] + + +class SavedLocationTextText(BaseModel): + byte_offset: int + + +class SavedLocationText(BaseModel): + text: SavedLocationTextText = FieldInfo(alias="Text") + + +class SavedLocationVisualVisual(BaseModel): + x: int + + y: int + + +class SavedLocationVisual(BaseModel): + visual: SavedLocationVisualVisual = FieldInfo(alias="Visual") + + +class SavedLocationPagePage(BaseModel): + page_number: int + + +class SavedLocationPage(BaseModel): + page: SavedLocationPagePage = FieldInfo(alias="Page") + + +SavedLocation: TypeAlias = Union[SavedLocationText, SavedLocationVisual, SavedLocationPage, None] + + +class Saved(BaseModel): + id: str + + created_at: datetime + + is_summary: bool + + label: str + + llm_id: int + + properties: Dict[str, SavedProperties] + + source_id: str + + user_specified: bool + + job_id: Optional[str] = None + + kg_entity_id: Optional[str] = None + + link: Optional[Source] = None + + location: Optional[SavedLocation] = None + + scraper_id: Optional[str] = None + + +class JobGetResponse(BaseModel): + agents: List[Agent] + + info: Info + + saved: List[List[Saved]] diff --git a/src/structify/types/job_get_scrapers_response.py b/src/structify/types/job_get_scrapers_response.py deleted file mode 100644 index d22f6a616..000000000 --- a/src/structify/types/job_get_scrapers_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import TypeAlias - -from .._models import BaseModel -from .chat_event import ChatEvent -from .chat_prompt import ChatPrompt - -__all__ = ["JobGetScrapersResponse", "JobGetScrapersResponseItem"] - - -class JobGetScrapersResponseItem(BaseModel): - base_url: str - - is_newly_created: bool - - scraper_created_at: datetime - - scraper_id: str - - scraper_updated_at: datetime - - chat: Optional[ChatPrompt] = None - - code: Optional[str] = None - - events: Optional[List[ChatEvent]] = None - - next_page_code: Optional[str] = None - - -JobGetScrapersResponse: TypeAlias = List[JobGetScrapersResponseItem] diff --git a/src/structify/types/job_get_source_entities_response.py b/src/structify/types/job_get_source_entities_response.py deleted file mode 100644 index a43f7932b..000000000 --- a/src/structify/types/job_get_source_entities_response.py +++ /dev/null @@ -1,170 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from pydantic import Field as FieldInfo - -from .image import Image -from .source import Source -from .._models import BaseModel - -__all__ = [ - "JobGetSourceEntitiesResponse", - "SourceEntity", - "SourceEntityProperties", - "SourceEntityPropertiesPartialDateObject", - "SourceEntityPropertiesURLObject", - "SourceEntityPropertiesMoneyObject", - "SourceEntityPropertiesPersonName", - "SourceEntityPropertiesAddressObject", - "SourceEntityLocation", - "SourceEntityLocationText", - "SourceEntityLocationTextText", - "SourceEntityLocationVisual", - "SourceEntityLocationVisualVisual", - "SourceEntityLocationPage", - "SourceEntityLocationPagePage", -] - - -class SourceEntityPropertiesPartialDateObject(BaseModel): - original_string: str - - year: int - - day: Optional[int] = None - - month: Optional[int] = None - - -class SourceEntityPropertiesURLObject(BaseModel): - original_string: str - - url: str - - -class SourceEntityPropertiesMoneyObject(BaseModel): - amount: float - - currency_code: Literal[ - "USD", - "EUR", - "GBP", - "JPY", - "CNY", - "INR", - "RUB", - "CAD", - "AUD", - "CHF", - "ILS", - "NZD", - "SGD", - "HKD", - "NOK", - "SEK", - "PLN", - "TRY", - "DKK", - "MXN", - "ZAR", - "PHP", - "VND", - "THB", - "BRL", - "KRW", - ] - - original_string: str - - -class SourceEntityPropertiesPersonName(BaseModel): - name: str - - -class SourceEntityPropertiesAddressObject(BaseModel): - components: Dict[str, str] - - original_address: str - - -SourceEntityProperties: TypeAlias = Union[ - str, - bool, - float, - SourceEntityPropertiesPartialDateObject, - str, - str, - SourceEntityPropertiesURLObject, - str, - SourceEntityPropertiesMoneyObject, - Image, - SourceEntityPropertiesPersonName, - SourceEntityPropertiesAddressObject, - str, -] - - -class SourceEntityLocationTextText(BaseModel): - byte_offset: int - - -class SourceEntityLocationText(BaseModel): - text: SourceEntityLocationTextText = FieldInfo(alias="Text") - - -class SourceEntityLocationVisualVisual(BaseModel): - x: int - - y: int - - -class SourceEntityLocationVisual(BaseModel): - visual: SourceEntityLocationVisualVisual = FieldInfo(alias="Visual") - - -class SourceEntityLocationPagePage(BaseModel): - page_number: int - - -class SourceEntityLocationPage(BaseModel): - page: SourceEntityLocationPagePage = FieldInfo(alias="Page") - - -SourceEntityLocation: TypeAlias = Union[ - SourceEntityLocationText, SourceEntityLocationVisual, SourceEntityLocationPage, None -] - - -class SourceEntity(BaseModel): - id: str - - created_at: datetime - - is_summary: bool - - label: str - - llm_id: int - - properties: Dict[str, SourceEntityProperties] - - source_id: str - - user_specified: bool - - job_id: Optional[str] = None - - kg_entity_id: Optional[str] = None - - link: Optional[Source] = None - - location: Optional[SourceEntityLocation] = None - - scraper_id: Optional[str] = None - - -class JobGetSourceEntitiesResponse(BaseModel): - source_entities: List[List[SourceEntity]] diff --git a/src/structify/types/job_list_params.py b/src/structify/types/job_list_params.py index e13064899..d93b17726 100644 --- a/src/structify/types/job_list_params.py +++ b/src/structify/types/job_list_params.py @@ -15,7 +15,7 @@ class JobListParams(TypedDict, total=False): dataset: Optional[str] """Dataset name to optionally filter jobs by""" - job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"]] + job_type: Optional[Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"]] """Type of job to optionally filter jobs by""" limit: int diff --git a/src/structify/types/job_list_response.py b/src/structify/types/job_list_response.py index 4ed6da86a..122fbeb06 100644 --- a/src/structify/types/job_list_response.py +++ b/src/structify/types/job_list_response.py @@ -26,6 +26,8 @@ "ParametersStructuringInputScrapeFromURLPropertyScrapeFromURLProperty", "ParametersStructuringInputScrapeURL", "ParametersStructuringInputScrapeURLScrapeURL", + "ParametersStructuringInputDatahubIngestion", + "ParametersStructuringInputDatahubIngestionDatahubIngestion", "ParametersStructuringInputConnectorExploration", "ParametersStructuringInputConnectorExplorationConnectorExploration", ] @@ -95,6 +97,18 @@ class ParametersStructuringInputScrapeURL(BaseModel): scrape_url: ParametersStructuringInputScrapeURLScrapeURL = FieldInfo(alias="ScrapeUrl") +class ParametersStructuringInputDatahubIngestionDatahubIngestion(BaseModel): + connector_id: str + + exploration_run_id: str + + only_do_datahub: bool + + +class ParametersStructuringInputDatahubIngestion(BaseModel): + datahub_ingestion: ParametersStructuringInputDatahubIngestionDatahubIngestion = FieldInfo(alias="DatahubIngestion") + + class ParametersStructuringInputConnectorExplorationConnectorExploration(BaseModel): connector_id: str @@ -107,8 +121,7 @@ class ParametersStructuringInputConnectorExplorationConnectorExploration(BaseMod exploration_run_id: str - stage: Literal["both", "ingestion", "annotation"] - """Which exploration stage to run""" + strategy: Literal["full", "diff"] class ParametersStructuringInputConnectorExploration(BaseModel): @@ -122,6 +135,7 @@ class ParametersStructuringInputConnectorExploration(BaseModel): ParametersStructuringInputTransformationPrompt, ParametersStructuringInputScrapeFromURLProperty, ParametersStructuringInputScrapeURL, + ParametersStructuringInputDatahubIngestion, ParametersStructuringInputConnectorExploration, ] @@ -131,33 +145,33 @@ class Parameters(BaseModel): extraction_criteria: List[SaveRequirement] - seeded_kg: KnowledgeGraph - """ - Knowledge graph info structured to deserialize and display in the same format - that the LLM outputs. Also the first representation of an LLM output in the - pipeline from raw tool output to being merged into a DB - """ - structuring_input: ParametersStructuringInput instructions: Optional[str] = None model: Optional[str] = None + seeded_kg: Optional[KnowledgeGraph] = None + """ + Knowledge graph info structured to deserialize and display in the same format + that the LLM outputs. Also the first representation of an LLM output in the + pipeline from raw tool output to being merged into a DB + """ + class JobListResponse(BaseModel): id: str created_at: datetime - dataset_id: str - - job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore"] + job_type: Literal["Web", "Pdf", "Derive", "Scrape", "Match", "ConnectorExplore", "DatahubIngestion"] status: Literal["Queued", "Running", "Completed", "Failed"] user_id: str + dataset_id: Optional[str] = None + message: Optional[str] = None parameters: Optional[Parameters] = None @@ -167,5 +181,3 @@ class JobListResponse(BaseModel): run_started_time: Optional[datetime] = None run_time_milliseconds: Optional[int] = None - - special_job_type: Optional[Literal["HumanLLM"]] = None diff --git a/src/structify/types/list_chat_sessions_response.py b/src/structify/types/list_chat_sessions_response.py index cdfc2307e..320833ee3 100644 --- a/src/structify/types/list_chat_sessions_response.py +++ b/src/structify/types/list_chat_sessions_response.py @@ -7,7 +7,7 @@ from .chat_visibility import ChatVisibility from .chat_session_role import ChatSessionRole -__all__ = ["ListChatSessionsResponse", "Session"] +__all__ = ["ListChatSessionsResponse", "Session", "TabCounts"] class Session(BaseModel): @@ -15,6 +15,8 @@ class Session(BaseModel): created_at: datetime + has_workflow_schedule: bool + is_favorite: bool team_id: str @@ -33,8 +35,36 @@ class Session(BaseModel): project_id: Optional[str] = None + slack_channel_id: Optional[str] = None + + teams_channel_id: Optional[str] = None + + teams_conversation_id: Optional[str] = None + + +class TabCounts(BaseModel): + """Per-tab counts for chat session listing""" + + favorites: int + + from_messaging: int + + my_chats: int + + recents: int + + shared: int + + team: int + class ListChatSessionsResponse(BaseModel): """Response for listing chat sessions""" sessions: List[Session] + + tab_counts: TabCounts + """Per-tab counts for chat session listing""" + + total_count: int + """Total number of chat sessions matching the query (for pagination)""" diff --git a/src/structify/types/list_dashboards_response.py b/src/structify/types/list_dashboards_response.py new file mode 100644 index 000000000..b25e00c74 --- /dev/null +++ b/src/structify/types/list_dashboards_response.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel +from .dashboard_item import DashboardItem + +__all__ = ["ListDashboardsResponse"] + + +class ListDashboardsResponse(BaseModel): + commit_hash: str + """Commit hash used to load dashboard specs.""" + + dashboards: List[DashboardItem] + """All dashboard specs in src/visualizations/\\**.viz.json.""" diff --git a/src/structify/types/llm_information_store.py b/src/structify/types/llm_information_store.py index b1a81a3d5..a8dde6fee 100644 --- a/src/structify/types/llm_information_store.py +++ b/src/structify/types/llm_information_store.py @@ -10,6 +10,8 @@ class DatabaseSchemaTableColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" diff --git a/src/structify/types/message_param.py b/src/structify/types/message_param.py new file mode 100644 index 000000000..8b5d1bcf9 --- /dev/null +++ b/src/structify/types/message_param.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import FileTypes +from .._utils import PropertyInfo + +__all__ = ["MessageParam", "Content", "ContentText", "ContentImage"] + + +class ContentText(TypedDict, total=False): + text: Required[Annotated[str, PropertyInfo(alias="Text")]] + + +class ContentImage(TypedDict, total=False): + image: Required[Annotated[FileTypes, PropertyInfo(alias="Image")]] + + +Content: TypeAlias = Union[ContentText, ContentImage] + + +class MessageParam(TypedDict, total=False): + """Our generic definition of a message to a chat agent.""" + + content: Required[Iterable[Content]] + """ + We want this to be a vec of contents so we can accurately capture an + interleaving of images and text. + + This is meant to be a completely raw, unprocessed representation of the text. + Don't take stuff out. + """ + + role: Required[Literal["user", "system", "assistant"]] diff --git a/src/structify/types/onboarding_answers.py b/src/structify/types/onboarding_answers.py new file mode 100644 index 000000000..d3d0be2a2 --- /dev/null +++ b/src/structify/types/onboarding_answers.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["OnboardingAnswers"] + + +class OnboardingAnswers(BaseModel): + company_name: Optional[str] = None + + connected_connector_ids: Optional[List[str]] = None + + full_name: Optional[str] = None + + primary_goal: Optional[str] = None + + recommended_template_id: Optional[str] = None + + role: Optional[str] = None + + systems_to_connect: Optional[List[str]] = None diff --git a/src/structify/types/onboarding_answers_param.py b/src/structify/types/onboarding_answers_param.py new file mode 100644 index 000000000..b3e43f9f8 --- /dev/null +++ b/src/structify/types/onboarding_answers_param.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import TypedDict + +from .._types import SequenceNotStr + +__all__ = ["OnboardingAnswersParam"] + + +class OnboardingAnswersParam(TypedDict, total=False): + company_name: Optional[str] + + connected_connector_ids: Optional[SequenceNotStr[str]] + + full_name: Optional[str] + + primary_goal: Optional[str] + + recommended_template_id: Optional[str] + + role: Optional[str] + + systems_to_connect: Optional[SequenceNotStr[str]] diff --git a/src/structify/types/phase_activity.py b/src/structify/types/phase_activity.py new file mode 100644 index 000000000..63e43ac12 --- /dev/null +++ b/src/structify/types/phase_activity.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .exploration_phase_id import ExplorationPhaseID + +__all__ = ["PhaseActivity"] + + +class PhaseActivity(BaseModel): + job_id: str + + phase_id: ExplorationPhaseID + """Identifies the phase of connector exploration + + This enum is used to track which phase of exploration a chat session belongs to. + It's stored as JSONB in the database to allow for flexible phase identification. + """ + + status: Literal["Queued", "Running", "Completed", "Failed"] + + chat_id: Optional[str] = None diff --git a/src/structify/types/sandbox.py b/src/structify/types/sandbox.py index 37e213da1..ce0ca3756 100644 --- a/src/structify/types/sandbox.py +++ b/src/structify/types/sandbox.py @@ -18,7 +18,9 @@ class Sandbox(BaseModel): provider_id: str - status: Literal["alive", "terminated"] + status: Literal["alive", "paused", "terminated"] + + team_id: str updated_at: datetime @@ -30,6 +32,8 @@ class Sandbox(BaseModel): latest_node: Optional[str] = None + resumed_at: Optional[datetime] = None + session_id: Optional[str] = None tunnel_url: Optional[str] = None diff --git a/src/structify/types/sandbox_get_metrics_response.py b/src/structify/types/sandbox_get_metrics_response.py new file mode 100644 index 000000000..bb9d4ee97 --- /dev/null +++ b/src/structify/types/sandbox_get_metrics_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["SandboxGetMetricsResponse", "Memory", "Process", "Sandbox"] + + +class Memory(BaseModel): + available_mb: float + + percent: float + + total_mb: float + + used_mb: float + + +class Process(BaseModel): + cpu_percent: float + + memory_mb: float + + +class Sandbox(BaseModel): + remaining_seconds: int + + start_time: float + + total_timeout_seconds: int + + uptime_seconds: int + + +class SandboxGetMetricsResponse(BaseModel): + cpu_percent: float + + memory: Memory + + process: Process + + sandbox: Sandbox diff --git a/src/structify/types/save_onboarding_answers_response.py b/src/structify/types/save_onboarding_answers_response.py new file mode 100644 index 000000000..03ee078f3 --- /dev/null +++ b/src/structify/types/save_onboarding_answers_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .onboarding_answers import OnboardingAnswers + +__all__ = ["SaveOnboardingAnswersResponse"] + + +class SaveOnboardingAnswersResponse(BaseModel): + answers: OnboardingAnswers diff --git a/src/structify/types/session_create_session_params.py b/src/structify/types/session_create_session_params.py index df1aae369..2f08f0c31 100644 --- a/src/structify/types/session_create_session_params.py +++ b/src/structify/types/session_create_session_params.py @@ -11,6 +11,6 @@ class SessionCreateSessionParams(TypedDict, total=False): chat_session_id: Required[str] - git_commit: Required[str] + parent_chat_message_id: Optional[str] workflow_schedule_id: Optional[str] diff --git a/src/structify/types/session_upload_dashboard_layout_params.py b/src/structify/types/session_upload_dashboard_layout_params.py index 039ff7441..9404afd61 100644 --- a/src/structify/types/session_upload_dashboard_layout_params.py +++ b/src/structify/types/session_upload_dashboard_layout_params.py @@ -2,16 +2,31 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict from .dashboard_param import DashboardParam +from .dashboard_spec_param import DashboardSpecParam -__all__ = ["SessionUploadDashboardLayoutParams"] +__all__ = ["SessionUploadDashboardLayoutParams", "Variant0", "Variant1", "Variant1DashboardSpec"] -class SessionUploadDashboardLayoutParams(TypedDict, total=False): +class Variant0(TypedDict, total=False): layout: Required[DashboardParam] """ A page is the top-level container with title/description Can contain multiple dashboards with different datasets """ + + +class Variant1(TypedDict, total=False): + dashboard_specs: Required[Iterable[Variant1DashboardSpec]] + + +class Variant1DashboardSpec(TypedDict, total=False): + file_name: Required[str] + + spec: Required[DashboardSpecParam] + + +SessionUploadDashboardLayoutParams: TypeAlias = Union[Variant0, Variant1] diff --git a/src/structify/types/session_upload_node_output_data_params.py b/src/structify/types/session_upload_node_output_data_params.py index 35ee81397..dcc0b284c 100644 --- a/src/structify/types/session_upload_node_output_data_params.py +++ b/src/structify/types/session_upload_node_output_data_params.py @@ -13,4 +13,16 @@ class SessionUploadNodeOutputDataParams(TypedDict, total=False): content: Required[FileTypes] + cache_final_rows: Optional[int] + + cache_final_size_bytes: Optional[int] + + cache_max_bytes: Optional[int] + + cache_original_rows: Optional[int] + + cache_original_size_bytes: Optional[int] + + cache_truncated: Optional[bool] + output_schema: Optional[str] diff --git a/src/structify/types/simulate_prompt_response.py b/src/structify/types/simulate_prompt_response.py new file mode 100644 index 000000000..a6e39100a --- /dev/null +++ b/src/structify/types/simulate_prompt_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["SimulatePromptResponse"] + + +class SimulatePromptResponse(BaseModel): + response: str diff --git a/src/structify/types/structure_pdf_params.py b/src/structify/types/structure_pdf_params.py index e4c577e8b..48b2db292 100644 --- a/src/structify/types/structure_pdf_params.py +++ b/src/structify/types/structure_pdf_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict __all__ = ["StructurePdfParams"] @@ -15,8 +15,8 @@ class StructurePdfParams(TypedDict, total=False): instructions: Optional[str] - mode: Literal["Single", "Batch"] - model: Optional[str] node_id: Optional[str] + + pages: Optional[Iterable[int]] diff --git a/src/structify/types/team.py b/src/structify/types/team.py index cc1a46ccc..3d4a67f59 100644 --- a/src/structify/types/team.py +++ b/src/structify/types/team.py @@ -5,7 +5,19 @@ from .._models import BaseModel -__all__ = ["Team"] +__all__ = ["Team", "DaytonaCredentials", "WorkflowBucket"] + + +class DaytonaCredentials(BaseModel): + api_key: Optional[str] = None + + api_url: Optional[str] = None + + +class WorkflowBucket(BaseModel): + bucket_url: str + + gcp_credentials_json: Optional[str] = None class Team(BaseModel): @@ -17,9 +29,9 @@ class Team(BaseModel): updated_at: datetime - description: Optional[str] = None + daytona_credentials: Optional[DaytonaCredentials] = None - pipedream_project_id: Optional[str] = None + description: Optional[str] = None sandbox_provider: Optional[str] = None @@ -36,3 +48,5 @@ class Team(BaseModel): teams_service_url: Optional[str] = None teams_tenant_id: Optional[str] = None + + workflow_bucket: Optional[WorkflowBucket] = None diff --git a/src/structify/types/team_update_params.py b/src/structify/types/team_update_params.py index e671cbb8b..6beaeed9f 100644 --- a/src/structify/types/team_update_params.py +++ b/src/structify/types/team_update_params.py @@ -3,17 +3,19 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +from typing_extensions import Literal, Required, TypedDict -__all__ = ["TeamUpdateParams"] +__all__ = ["TeamUpdateParams", "DaytonaCredentials", "WorkflowBucket"] class TeamUpdateParams(TypedDict, total=False): + daytona_credentials: Optional[DaytonaCredentials] + description: Optional[str] name: Optional[str] - pipedream_project_id: Optional[str] + sandbox_provider: Optional[Literal["modal", "daytona"]] slack_bot_token: Optional[str] @@ -28,3 +30,17 @@ class TeamUpdateParams(TypedDict, total=False): teams_app_password: Optional[str] teams_tenant_id: Optional[str] + + workflow_bucket: Optional[WorkflowBucket] + + +class DaytonaCredentials(TypedDict, total=False): + api_key: Optional[str] + + api_url: Optional[str] + + +class WorkflowBucket(TypedDict, total=False): + bucket_url: Required[str] + + gcp_credentials_json: Optional[str] diff --git a/src/structify/types/template_question.py b/src/structify/types/template_question.py new file mode 100644 index 000000000..356e55278 --- /dev/null +++ b/src/structify/types/template_question.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["TemplateQuestion"] + + +class TemplateQuestion(BaseModel): + prompt: str + + options: Optional[List[str]] = None diff --git a/src/structify/types/template_question_param.py b/src/structify/types/template_question_param.py new file mode 100644 index 000000000..65cc0a2e2 --- /dev/null +++ b/src/structify/types/template_question_param.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Required, TypedDict + +from .._types import SequenceNotStr + +__all__ = ["TemplateQuestionParam"] + + +class TemplateQuestionParam(TypedDict, total=False): + prompt: Required[str] + + options: Optional[SequenceNotStr[str]] diff --git a/src/structify/types/tool_invocation.py b/src/structify/types/tool_invocation.py index 97fa0e021..6956a3018 100644 --- a/src/structify/types/tool_invocation.py +++ b/src/structify/types/tool_invocation.py @@ -36,6 +36,9 @@ "DeleteFileInput", "MoveFile", "MoveFileInput", + "ApplyPatch", + "ApplyPatchInput", + "ApplyPatchInputEdit", "RunBash", "RunBashInput", "RunPython", @@ -66,6 +69,10 @@ "CreateConnectorInput", "SearchConnectorTypes", "SearchConnectorTypesInput", + "PinPreviousTool", + "PinPreviousToolInput", + "RunPipeline", + "RunPipelineInput", ] @@ -191,12 +198,8 @@ class InspectStep(BaseModel): class ReadNodeLogsInput(BaseModel): - end_line: int - node_function_name: str - start_line: int - log_type: Optional[str] = None @@ -228,6 +231,26 @@ class MoveFile(BaseModel): name: Literal["MoveFile"] +class ApplyPatchInputEdit(BaseModel): + new_string: str + + old_string: str + + +class ApplyPatchInput(BaseModel): + apply_all: bool + + edits: List[ApplyPatchInputEdit] + + file: str + + +class ApplyPatch(BaseModel): + input: ApplyPatchInput + + name: Literal["ApplyPatch"] + + class RunBashInput(BaseModel): command: str @@ -307,8 +330,6 @@ class SaveTableInput(BaseModel): notes: Optional[str] = None - tag: Optional[str] = None - class SaveTable(BaseModel): input: SaveTableInput @@ -432,6 +453,26 @@ class SearchConnectorTypes(BaseModel): name: Literal["SearchConnectorTypes"] +class PinPreviousToolInput(BaseModel): + path: str + + +class PinPreviousTool(BaseModel): + input: PinPreviousToolInput + + name: Literal["PinPreviousTool"] + + +class RunPipelineInput(BaseModel): + rerun_all_steps: Optional[bool] = None + + +class RunPipeline(BaseModel): + input: RunPipelineInput + + name: Literal["RunPipeline"] + + ToolInvocation: TypeAlias = Annotated[ Union[ WebSearch, @@ -448,6 +489,7 @@ class SearchConnectorTypes(BaseModel): ReadNodeLogs, DeleteFile, MoveFile, + ApplyPatch, RunBash, RunPython, IssueFound, @@ -463,6 +505,8 @@ class SearchConnectorTypes(BaseModel): SelectData, CreateConnector, SearchConnectorTypes, + PinPreviousTool, + RunPipeline, ], PropertyInfo(discriminator="name"), ] diff --git a/src/structify/types/tool_metadata.py b/src/structify/types/tool_metadata.py deleted file mode 100644 index a9e3f084c..000000000 --- a/src/structify/types/tool_metadata.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ToolMetadata"] - - -class ToolMetadata(BaseModel): - description: str - - name: Literal["Exit", "Save", "Wait", "Type", "Scroll", "ScrollToBottom", "Click", "Hover", "Error", "Google"] - - regex_validator: str diff --git a/src/structify/types/tool_result.py b/src/structify/types/tool_result.py index e81cdfc57..54ab93253 100644 --- a/src/structify/types/tool_result.py +++ b/src/structify/types/tool_result.py @@ -22,6 +22,7 @@ "NodeLogs", "Image", "ImageImage", + "Pinned", ] @@ -101,6 +102,10 @@ class Image(BaseModel): image: ImageImage = FieldInfo(alias="Image") +class Pinned(BaseModel): + pinned: str = FieldInfo(alias="Pinned") + + ToolResult: TypeAlias = Union[ Literal["Pending", "NoResult", "Completed"], Error, @@ -111,4 +116,5 @@ class Image(BaseModel): ConnectorSearch, NodeLogs, Image, + Pinned, ] diff --git a/src/structify/types/trigger_review_response.py b/src/structify/types/trigger_review_response.py new file mode 100644 index 000000000..af114c75f --- /dev/null +++ b/src/structify/types/trigger_review_response.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["TriggerReviewResponse"] + + +class TriggerReviewResponse(BaseModel): + triggered: bool diff --git a/src/structify/types/update_table_response.py b/src/structify/types/update_table_response.py index a913c8a38..4ae117ce9 100644 --- a/src/structify/types/update_table_response.py +++ b/src/structify/types/update_table_response.py @@ -10,6 +10,8 @@ class TableColumn(BaseModel): """Represents a column in a table or API resource""" + id: str + name: str """Name of the column""" diff --git a/src/structify/types/upload_dashboard_layout_request_param.py b/src/structify/types/upload_dashboard_layout_request_param.py new file mode 100644 index 000000000..972cd55ed --- /dev/null +++ b/src/structify/types/upload_dashboard_layout_request_param.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from typing_extensions import Required, TypeAlias, TypedDict + +from .dashboard_param import DashboardParam +from .dashboard_spec_param import DashboardSpecParam + +__all__ = ["UploadDashboardLayoutRequestParam", "Layout", "DashboardSpecs", "DashboardSpecsDashboardSpec"] + + +class Layout(TypedDict, total=False): + layout: Required[DashboardParam] + """ + A page is the top-level container with title/description Can contain multiple + dashboards with different datasets + """ + + +class DashboardSpecsDashboardSpec(TypedDict, total=False): + file_name: Required[str] + + spec: Required[DashboardSpecParam] + + +class DashboardSpecs(TypedDict, total=False): + dashboard_specs: Required[Iterable[DashboardSpecsDashboardSpec]] + + +UploadDashboardLayoutRequestParam: TypeAlias = Union[Layout, DashboardSpecs] diff --git a/src/structify/types/user_info.py b/src/structify/types/user_info.py index 32a8d4e7e..7532590e7 100644 --- a/src/structify/types/user_info.py +++ b/src/structify/types/user_info.py @@ -34,7 +34,7 @@ class UserInfo(BaseModel): full_name: str - is_developer: bool + notify_for_interaction: bool permissions: List[Literal["labeler", "qa_labeler", "debug", "human_llm", "none"]] diff --git a/src/structify/types/user_save_onboarding_answers_params.py b/src/structify/types/user_save_onboarding_answers_params.py new file mode 100644 index 000000000..4689e70ae --- /dev/null +++ b/src/structify/types/user_save_onboarding_answers_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .onboarding_answers_param import OnboardingAnswersParam + +__all__ = ["UserSaveOnboardingAnswersParams"] + + +class UserSaveOnboardingAnswersParams(TypedDict, total=False): + answers: Required[OnboardingAnswersParam] diff --git a/src/structify/types/user_update_params.py b/src/structify/types/user_update_params.py index 9db7c6e9a..9c1616109 100644 --- a/src/structify/types/user_update_params.py +++ b/src/structify/types/user_update_params.py @@ -54,14 +54,14 @@ class Updates(TypedDict, total=False): full_name: Optional[str] - is_developer: Optional[bool] - job_title: Optional[str] last_selected_team_id: Optional[str] linkedin_url: Optional[str] + notify_for_interaction: Optional[bool] + onboarding_session_id: Optional[str] permissions: Optional[List[Optional[Literal["labeler", "qa_labeler", "debug", "human_llm", "none"]]]] diff --git a/src/structify/types/viz_boolean_control.py b/src/structify/types/viz_boolean_control.py new file mode 100644 index 000000000..7b217fd44 --- /dev/null +++ b/src/structify/types/viz_boolean_control.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .viz_boolean_control_type import VizBooleanControlType + +__all__ = ["VizBooleanControl"] + + +class VizBooleanControl(BaseModel): + label: str + + type: VizBooleanControlType diff --git a/src/structify/types/viz_boolean_control_param.py b/src/structify/types/viz_boolean_control_param.py new file mode 100644 index 000000000..866601613 --- /dev/null +++ b/src/structify/types/viz_boolean_control_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .viz_boolean_control_type import VizBooleanControlType + +__all__ = ["VizBooleanControlParam"] + + +class VizBooleanControlParam(TypedDict, total=False): + label: Required[str] + + type: Required[VizBooleanControlType] diff --git a/src/structify/types/viz_boolean_control_type.py b/src/structify/types/viz_boolean_control_type.py new file mode 100644 index 000000000..be767552e --- /dev/null +++ b/src/structify/types/viz_boolean_control_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VizBooleanControlType"] + +VizBooleanControlType: TypeAlias = Literal["checkbox"] diff --git a/src/structify/types/viz_control_option.py b/src/structify/types/viz_control_option.py new file mode 100644 index 000000000..dfe26755e --- /dev/null +++ b/src/structify/types/viz_control_option.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["VizControlOption"] + + +class VizControlOption(BaseModel): + label: str + + value: str diff --git a/src/structify/types/viz_control_option_param.py b/src/structify/types/viz_control_option_param.py new file mode 100644 index 000000000..b6edd6bc1 --- /dev/null +++ b/src/structify/types/viz_control_option_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VizControlOptionParam"] + + +class VizControlOptionParam(TypedDict, total=False): + label: Required[str] + + value: Required[str] diff --git a/src/structify/types/viz_date_control.py b/src/structify/types/viz_date_control.py new file mode 100644 index 000000000..397dbe4a5 --- /dev/null +++ b/src/structify/types/viz_date_control.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .viz_date_control_type import VizDateControlType + +__all__ = ["VizDateControl"] + + +class VizDateControl(BaseModel): + label: str + + type: VizDateControlType diff --git a/src/structify/types/viz_date_control_param.py b/src/structify/types/viz_date_control_param.py new file mode 100644 index 000000000..32ed102e4 --- /dev/null +++ b/src/structify/types/viz_date_control_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .viz_date_control_type import VizDateControlType + +__all__ = ["VizDateControlParam"] + + +class VizDateControlParam(TypedDict, total=False): + label: Required[str] + + type: Required[VizDateControlType] diff --git a/src/structify/types/viz_date_control_type.py b/src/structify/types/viz_date_control_type.py new file mode 100644 index 000000000..a24b3f95c --- /dev/null +++ b/src/structify/types/viz_date_control_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VizDateControlType"] + +VizDateControlType: TypeAlias = Literal["date"] diff --git a/src/structify/types/viz_figure.py b/src/structify/types/viz_figure.py new file mode 100644 index 000000000..dab6b01c6 --- /dev/null +++ b/src/structify/types/viz_figure.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .viz_figure_definition import VizFigureDefinition + +__all__ = ["VizFigure"] + + +class VizFigure(BaseModel): + id: str + + figure: VizFigureDefinition + + description: Optional[str] = None + + span: Optional[int] = None + + title: Optional[str] = None diff --git a/src/structify/types/viz_figure_definition.py b/src/structify/types/viz_figure_definition.py new file mode 100644 index 000000000..9928e4e8a --- /dev/null +++ b/src/structify/types/viz_figure_definition.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel +from .viz_figure_kind import VizFigureKind + +__all__ = ["VizFigureDefinition"] + + +class VizFigureDefinition(BaseModel): + expression: str + + kind: VizFigureKind diff --git a/src/structify/types/viz_figure_definition_param.py b/src/structify/types/viz_figure_definition_param.py new file mode 100644 index 000000000..1f26b349a --- /dev/null +++ b/src/structify/types/viz_figure_definition_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .viz_figure_kind import VizFigureKind + +__all__ = ["VizFigureDefinitionParam"] + + +class VizFigureDefinitionParam(TypedDict, total=False): + expression: Required[str] + + kind: Required[VizFigureKind] diff --git a/src/structify/types/viz_figure_kind.py b/src/structify/types/viz_figure_kind.py new file mode 100644 index 000000000..e70d16356 --- /dev/null +++ b/src/structify/types/viz_figure_kind.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VizFigureKind"] + +VizFigureKind: TypeAlias = Literal["js", "vega-lite", "data-table"] diff --git a/src/structify/types/viz_figure_param.py b/src/structify/types/viz_figure_param.py new file mode 100644 index 000000000..e76dd3968 --- /dev/null +++ b/src/structify/types/viz_figure_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .viz_figure_definition_param import VizFigureDefinitionParam + +__all__ = ["VizFigureParam"] + + +class VizFigureParam(TypedDict, total=False): + id: Required[str] + + figure: Required[VizFigureDefinitionParam] + + description: str + + span: int + + title: str diff --git a/src/structify/types/viz_number_control.py b/src/structify/types/viz_number_control.py new file mode 100644 index 000000000..efdc9d22e --- /dev/null +++ b/src/structify/types/viz_number_control.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .viz_number_control_type import VizNumberControlType + +__all__ = ["VizNumberControl"] + + +class VizNumberControl(BaseModel): + label: str + + max: float + + min: float + + type: VizNumberControlType + + step: Optional[float] = None diff --git a/src/structify/types/viz_number_control_param.py b/src/structify/types/viz_number_control_param.py new file mode 100644 index 000000000..2d511b586 --- /dev/null +++ b/src/structify/types/viz_number_control_param.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .viz_number_control_type import VizNumberControlType + +__all__ = ["VizNumberControlParam"] + + +class VizNumberControlParam(TypedDict, total=False): + label: Required[str] + + max: Required[float] + + min: Required[float] + + type: Required[VizNumberControlType] + + step: float diff --git a/src/structify/types/viz_number_control_type.py b/src/structify/types/viz_number_control_type.py new file mode 100644 index 000000000..30ffa1301 --- /dev/null +++ b/src/structify/types/viz_number_control_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VizNumberControlType"] + +VizNumberControlType: TypeAlias = Literal["range"] diff --git a/src/structify/types/viz_param.py b/src/structify/types/viz_param.py new file mode 100644 index 000000000..83e779bb8 --- /dev/null +++ b/src/structify/types/viz_param.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .viz_date_control import VizDateControl +from .viz_number_control import VizNumberControl +from .viz_string_control import VizStringControl +from .viz_boolean_control import VizBooleanControl + +__all__ = ["VizParam", "String", "Number", "Boolean", "Date"] + + +class String(BaseModel): + type: Literal["string"] + + value: str + + control: Optional[VizStringControl] = None + + +class Number(BaseModel): + type: Literal["number"] + + value: float + + control: Optional[VizNumberControl] = None + + +class Boolean(BaseModel): + type: Literal["boolean"] + + value: bool + + control: Optional[VizBooleanControl] = None + + +class Date(BaseModel): + type: Literal["date"] + + value: str + + control: Optional[VizDateControl] = None + + +VizParam: TypeAlias = Annotated[Union[String, Number, Boolean, Date], PropertyInfo(discriminator="type")] diff --git a/src/structify/types/viz_param_param.py b/src/structify/types/viz_param_param.py new file mode 100644 index 000000000..ca0d8f6a1 --- /dev/null +++ b/src/structify/types/viz_param_param.py @@ -0,0 +1,48 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .viz_date_control_param import VizDateControlParam +from .viz_number_control_param import VizNumberControlParam +from .viz_string_control_param import VizStringControlParam +from .viz_boolean_control_param import VizBooleanControlParam + +__all__ = ["VizParamParam", "String", "Number", "Boolean", "Date"] + + +class String(TypedDict, total=False): + type: Required[Literal["string"]] + + value: Required[str] + + control: VizStringControlParam + + +class Number(TypedDict, total=False): + type: Required[Literal["number"]] + + value: Required[float] + + control: VizNumberControlParam + + +class Boolean(TypedDict, total=False): + type: Required[Literal["boolean"]] + + value: Required[bool] + + control: VizBooleanControlParam + + +class Date(TypedDict, total=False): + type: Required[Literal["date"]] + + value: Required[str] + + control: VizDateControlParam + + +VizParamParam: TypeAlias = Union[String, Number, Boolean, Date] diff --git a/src/structify/types/viz_query.py b/src/structify/types/viz_query.py new file mode 100644 index 000000000..e6c751625 --- /dev/null +++ b/src/structify/types/viz_query.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["VizQuery"] + + +class VizQuery(BaseModel): + id: str + + sql: str diff --git a/src/structify/types/viz_query_param.py b/src/structify/types/viz_query_param.py new file mode 100644 index 000000000..71aad068a --- /dev/null +++ b/src/structify/types/viz_query_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VizQueryParam"] + + +class VizQueryParam(TypedDict, total=False): + id: Required[str] + + sql: Required[str] diff --git a/src/structify/types/viz_string_control.py b/src/structify/types/viz_string_control.py new file mode 100644 index 000000000..fbb70d640 --- /dev/null +++ b/src/structify/types/viz_string_control.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel +from .viz_control_option import VizControlOption +from .viz_string_control_type import VizStringControlType + +__all__ = ["VizStringControl"] + + +class VizStringControl(BaseModel): + label: str + + options: List[VizControlOption] + + type: VizStringControlType diff --git a/src/structify/types/viz_string_control_param.py b/src/structify/types/viz_string_control_param.py new file mode 100644 index 000000000..f01adeb0d --- /dev/null +++ b/src/structify/types/viz_string_control_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .viz_string_control_type import VizStringControlType +from .viz_control_option_param import VizControlOptionParam + +__all__ = ["VizStringControlParam"] + + +class VizStringControlParam(TypedDict, total=False): + label: Required[str] + + options: Required[Iterable[VizControlOptionParam]] + + type: Required[VizStringControlType] diff --git a/src/structify/types/viz_string_control_type.py b/src/structify/types/viz_string_control_type.py new file mode 100644 index 000000000..fa2b28c76 --- /dev/null +++ b/src/structify/types/viz_string_control_type.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["VizStringControlType"] + +VizStringControlType: TypeAlias = Literal["dropdown"] diff --git a/src/structify/types/workflow_dag.py b/src/structify/types/workflow_dag.py index 2a0f0470f..d896e6210 100644 --- a/src/structify/types/workflow_dag.py +++ b/src/structify/types/workflow_dag.py @@ -5,6 +5,7 @@ from .._models import BaseModel from .dashboard import Dashboard +from .dashboard_item import DashboardItem from .workflow_session_edge import WorkflowSessionEdge from .workflow_session_node import WorkflowSessionNode @@ -14,6 +15,8 @@ class WorkflowDag(BaseModel): aborted: bool + dashboard_specs: List[DashboardItem] + edges: List[WorkflowSessionEdge] is_ready: bool diff --git a/src/structify/types/workflow_schedule_info.py b/src/structify/types/workflow_schedule_info.py index a0e9bf44d..eae143b7e 100644 --- a/src/structify/types/workflow_schedule_info.py +++ b/src/structify/types/workflow_schedule_info.py @@ -3,6 +3,7 @@ from typing import Optional from .._models import BaseModel +from .chat_visibility import ChatVisibility __all__ = ["WorkflowScheduleInfo"] @@ -21,3 +22,9 @@ class WorkflowScheduleInfo(BaseModel): git_commit_hash: Optional[str] = None next_run_time: Optional[str] = None + + owner_email: Optional[str] = None + + updated_at: Optional[str] = None + + visibility: Optional[ChatVisibility] = None diff --git a/src/structify/types/workflow_session.py b/src/structify/types/workflow_session.py index dfbcdbd57..49284cb58 100644 --- a/src/structify/types/workflow_session.py +++ b/src/structify/types/workflow_session.py @@ -29,6 +29,6 @@ class WorkflowSession(BaseModel): error_traceback: Optional[str] = None - git_commit: Optional[str] = None + parent_chat_message_id: Optional[str] = None workflow_schedule_id: Optional[str] = None diff --git a/src/structify/types/workflow_session_node.py b/src/structify/types/workflow_session_node.py index a790119d5..0f93d2b48 100644 --- a/src/structify/types/workflow_session_node.py +++ b/src/structify/types/workflow_session_node.py @@ -30,6 +30,18 @@ class WorkflowSessionNode(BaseModel): updated_at: datetime + cache_final_rows: Optional[int] = None + + cache_final_size_bytes: Optional[int] = None + + cache_max_bytes: Optional[int] = None + + cache_original_rows: Optional[int] = None + + cache_original_size_bytes: Optional[int] = None + + cache_truncated: Optional[bool] = None + code: Optional[str] = None confirmation_status: Optional[str] = None diff --git a/tests/api_resources/admin/test_chat_templates.py b/tests/api_resources/admin/test_chat_templates.py index e33d109bf..8d8115368 100644 --- a/tests/api_resources/admin/test_chat_templates.py +++ b/tests/api_resources/admin/test_chat_templates.py @@ -28,6 +28,7 @@ def test_method_create(self, client: Structify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) assert_matches_type(ChatTemplate, chat_template, path=["response"]) @@ -40,6 +41,7 @@ def test_raw_response_create(self, client: Structify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) @@ -56,6 +58,7 @@ def test_streaming_response_create(self, client: Structify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) as response: assert not response.is_closed @@ -81,6 +84,12 @@ def test_method_update_with_all_params(self, client: Structify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[ + { + "prompt": "prompt", + "options": ["string"], + } + ], title="title", updated_by="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) @@ -163,6 +172,7 @@ async def test_method_create(self, async_client: AsyncStructify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) assert_matches_type(ChatTemplate, chat_template, path=["response"]) @@ -175,6 +185,7 @@ async def test_raw_response_create(self, async_client: AsyncStructify) -> None: display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) @@ -191,6 +202,7 @@ async def test_streaming_response_create(self, async_client: AsyncStructify) -> display_order=0, image_url="image_url", is_active=True, + questions=[{"prompt": "prompt"}], title="title", ) as response: assert not response.is_closed @@ -216,6 +228,12 @@ async def test_method_update_with_all_params(self, async_client: AsyncStructify) display_order=0, image_url="image_url", is_active=True, + questions=[ + { + "prompt": "prompt", + "options": ["string"], + } + ], title="title", updated_by="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) diff --git a/tests/api_resources/admin/test_connector.py b/tests/api_resources/admin/test_connector.py index 3535580ac..7d2a3c984 100644 --- a/tests/api_resources/admin/test_connector.py +++ b/tests/api_resources/admin/test_connector.py @@ -9,7 +9,11 @@ from structify import Structify, AsyncStructify from tests.utils import assert_matches_type -from structify.types.admin import CloneConnectorsResponse +from structify.types import Connector +from structify.types.admin import ( + ConnectorCloneResponse, + AdminListConnectorsResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -27,9 +31,11 @@ def test_method_clone(self, client: Structify) -> None: "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) @parametrize def test_raw_response_clone(self, client: Structify) -> None: @@ -41,13 +47,15 @@ def test_raw_response_clone(self, client: Structify) -> None: "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) @parametrize def test_streaming_response_clone(self, client: Structify) -> None: @@ -59,13 +67,93 @@ def test_streaming_response_clone(self, client: Structify) -> None: "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list_team_connectors(self, client: Structify) -> None: + connector = client.admin.connector.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + @parametrize + def test_raw_response_list_team_connectors(self, client: Structify) -> None: + response = client.admin.connector.with_raw_response.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + @parametrize + def test_streaming_response_list_team_connectors(self, client: Structify) -> None: + with client.admin.connector.with_streaming_response.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_team_connectors(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `team_id` but received ''"): + client.admin.connector.with_raw_response.list_team_connectors( + "", + ) + + @parametrize + def test_method_set_datahub_config(self, client: Structify) -> None: + connector = client.admin.connector.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + def test_method_set_datahub_config_with_all_params(self, client: Structify) -> None: + connector = client.admin.connector.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + datahub_ingestion_type="postgres", + datahub_secret_map={"foo": "string"}, + ) + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + def test_raw_response_set_datahub_config(self, client: Structify) -> None: + response = client.admin.connector.with_raw_response.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + def test_streaming_response_set_datahub_config(self, client: Structify) -> None: + with client.admin.connector.with_streaming_response.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert_matches_type(Connector, connector, path=["response"]) assert cast(Any, response.is_closed) is True @@ -85,9 +173,11 @@ async def test_method_clone(self, async_client: AsyncStructify) -> None: "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) @parametrize async def test_raw_response_clone(self, async_client: AsyncStructify) -> None: @@ -99,13 +189,15 @@ async def test_raw_response_clone(self, async_client: AsyncStructify) -> None: "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) @parametrize async def test_streaming_response_clone(self, async_client: AsyncStructify) -> None: @@ -117,12 +209,92 @@ async def test_streaming_response_clone(self, async_client: AsyncStructify) -> N "source_connector_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", } ], + source_membership_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + source_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", target_team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(CloneConnectorsResponse, connector, path=["response"]) + assert_matches_type(ConnectorCloneResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list_team_connectors(self, async_client: AsyncStructify) -> None: + connector = await async_client.admin.connector.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + @parametrize + async def test_raw_response_list_team_connectors(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.connector.with_raw_response.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + @parametrize + async def test_streaming_response_list_team_connectors(self, async_client: AsyncStructify) -> None: + async with async_client.admin.connector.with_streaming_response.list_team_connectors( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert_matches_type(AdminListConnectorsResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_team_connectors(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `team_id` but received ''"): + await async_client.admin.connector.with_raw_response.list_team_connectors( + "", + ) + + @parametrize + async def test_method_set_datahub_config(self, async_client: AsyncStructify) -> None: + connector = await async_client.admin.connector.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + async def test_method_set_datahub_config_with_all_params(self, async_client: AsyncStructify) -> None: + connector = await async_client.admin.connector.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + datahub_ingestion_type="postgres", + datahub_secret_map={"foo": "string"}, + ) + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + async def test_raw_response_set_datahub_config(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.connector.with_raw_response.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert_matches_type(Connector, connector, path=["response"]) + + @parametrize + async def test_streaming_response_set_datahub_config(self, async_client: AsyncStructify) -> None: + async with async_client.admin.connector.with_streaming_response.set_datahub_config( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert_matches_type(Connector, connector, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/test_jobs.py b/tests/api_resources/admin/test_jobs.py index bfc2d0cea..2ae99cb3f 100644 --- a/tests/api_resources/admin/test_jobs.py +++ b/tests/api_resources/admin/test_jobs.py @@ -9,9 +9,15 @@ from structify import Structify, AsyncStructify from tests.utils import assert_matches_type -from structify._utils import parse_datetime from structify.pagination import SyncJobsList, AsyncJobsList -from structify.types.admin import AdminListJobsResponse, AdminDeleteJobsResponse +from structify.types.admin import ( + JobListResponse, + JobKillByUserResponse, + JobConcurrencyResponse, + AdminDeleteJobsResponse, + JobRunningStatsResponse, + JobUpdateConcurrencyResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -21,51 +27,37 @@ class TestJobs: @parametrize def test_method_list(self, client: Structify) -> None: - job = client.admin.jobs.list( - filter_test_users=True, - limit=0, - offset=0, - ) - assert_matches_type(SyncJobsList[AdminListJobsResponse], job, path=["response"]) + job = client.admin.jobs.list() + assert_matches_type(SyncJobsList[JobListResponse], job, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Structify) -> None: job = client.admin.jobs.list( - filter_test_users=True, + job_type="Web", limit=0, offset=0, - dataset_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - seeded_kg_search_term="seeded_kg_search_term", - since=parse_datetime("2019-12-27T18:11:19.117Z"), status="Queued", + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(SyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(SyncJobsList[JobListResponse], job, path=["response"]) @parametrize def test_raw_response_list(self, client: Structify) -> None: - response = client.admin.jobs.with_raw_response.list( - filter_test_users=True, - limit=0, - offset=0, - ) + response = client.admin.jobs.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(SyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(SyncJobsList[JobListResponse], job, path=["response"]) @parametrize def test_streaming_response_list(self, client: Structify) -> None: - with client.admin.jobs.with_streaming_response.list( - filter_test_users=True, - limit=0, - offset=0, - ) as response: + with client.admin.jobs.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(SyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(SyncJobsList[JobListResponse], job, path=["response"]) assert cast(Any, response.is_closed) is True @@ -100,6 +92,125 @@ def test_streaming_response_delete(self, client: Structify) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_concurrency(self, client: Structify) -> None: + job = client.admin.jobs.concurrency() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + @parametrize + def test_raw_response_concurrency(self, client: Structify) -> None: + response = client.admin.jobs.with_raw_response.concurrency() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + @parametrize + def test_streaming_response_concurrency(self, client: Structify) -> None: + with client.admin.jobs.with_streaming_response.concurrency() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_kill_by_user(self, client: Structify) -> None: + job = client.admin.jobs.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + @parametrize + def test_raw_response_kill_by_user(self, client: Structify) -> None: + response = client.admin.jobs.with_raw_response.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + @parametrize + def test_streaming_response_kill_by_user(self, client: Structify) -> None: + with client.admin.jobs.with_streaming_response.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_running_stats(self, client: Structify) -> None: + job = client.admin.jobs.running_stats() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + @parametrize + def test_raw_response_running_stats(self, client: Structify) -> None: + response = client.admin.jobs.with_raw_response.running_stats() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + @parametrize + def test_streaming_response_running_stats(self, client: Structify) -> None: + with client.admin.jobs.with_streaming_response.running_stats() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_concurrency(self, client: Structify) -> None: + job = client.admin.jobs.update_concurrency() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + def test_method_update_concurrency_with_all_params(self, client: Structify) -> None: + job = client.admin.jobs.update_concurrency( + max_connector_explore_jobs=0, + max_derive_jobs=0, + max_match_jobs=0, + max_pdf_jobs=0, + max_scrape_jobs=0, + max_total_jobs=0, + max_web_jobs=0, + ) + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + def test_raw_response_update_concurrency(self, client: Structify) -> None: + response = client.admin.jobs.with_raw_response.update_concurrency() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + def test_streaming_response_update_concurrency(self, client: Structify) -> None: + with client.admin.jobs.with_streaming_response.update_concurrency() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncJobs: parametrize = pytest.mark.parametrize( @@ -108,51 +219,37 @@ class TestAsyncJobs: @parametrize async def test_method_list(self, async_client: AsyncStructify) -> None: - job = await async_client.admin.jobs.list( - filter_test_users=True, - limit=0, - offset=0, - ) - assert_matches_type(AsyncJobsList[AdminListJobsResponse], job, path=["response"]) + job = await async_client.admin.jobs.list() + assert_matches_type(AsyncJobsList[JobListResponse], job, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncStructify) -> None: job = await async_client.admin.jobs.list( - filter_test_users=True, + job_type="Web", limit=0, offset=0, - dataset_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - seeded_kg_search_term="seeded_kg_search_term", - since=parse_datetime("2019-12-27T18:11:19.117Z"), status="Queued", + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(AsyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(AsyncJobsList[JobListResponse], job, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncStructify) -> None: - response = await async_client.admin.jobs.with_raw_response.list( - filter_test_users=True, - limit=0, - offset=0, - ) + response = await async_client.admin.jobs.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(AsyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(AsyncJobsList[JobListResponse], job, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncStructify) -> None: - async with async_client.admin.jobs.with_streaming_response.list( - filter_test_users=True, - limit=0, - offset=0, - ) as response: + async with async_client.admin.jobs.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(AsyncJobsList[AdminListJobsResponse], job, path=["response"]) + assert_matches_type(AsyncJobsList[JobListResponse], job, path=["response"]) assert cast(Any, response.is_closed) is True @@ -186,3 +283,122 @@ async def test_streaming_response_delete(self, async_client: AsyncStructify) -> assert_matches_type(AdminDeleteJobsResponse, job, path=["response"]) assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_concurrency(self, async_client: AsyncStructify) -> None: + job = await async_client.admin.jobs.concurrency() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + @parametrize + async def test_raw_response_concurrency(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.jobs.with_raw_response.concurrency() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = await response.parse() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + @parametrize + async def test_streaming_response_concurrency(self, async_client: AsyncStructify) -> None: + async with async_client.admin.jobs.with_streaming_response.concurrency() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(JobConcurrencyResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_kill_by_user(self, async_client: AsyncStructify) -> None: + job = await async_client.admin.jobs.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + @parametrize + async def test_raw_response_kill_by_user(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.jobs.with_raw_response.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = await response.parse() + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + @parametrize + async def test_streaming_response_kill_by_user(self, async_client: AsyncStructify) -> None: + async with async_client.admin.jobs.with_streaming_response.kill_by_user( + user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(JobKillByUserResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_running_stats(self, async_client: AsyncStructify) -> None: + job = await async_client.admin.jobs.running_stats() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + @parametrize + async def test_raw_response_running_stats(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.jobs.with_raw_response.running_stats() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = await response.parse() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + @parametrize + async def test_streaming_response_running_stats(self, async_client: AsyncStructify) -> None: + async with async_client.admin.jobs.with_streaming_response.running_stats() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(JobRunningStatsResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_concurrency(self, async_client: AsyncStructify) -> None: + job = await async_client.admin.jobs.update_concurrency() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + async def test_method_update_concurrency_with_all_params(self, async_client: AsyncStructify) -> None: + job = await async_client.admin.jobs.update_concurrency( + max_connector_explore_jobs=0, + max_derive_jobs=0, + max_match_jobs=0, + max_pdf_jobs=0, + max_scrape_jobs=0, + max_total_jobs=0, + max_web_jobs=0, + ) + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + async def test_raw_response_update_concurrency(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.jobs.with_raw_response.update_concurrency() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = await response.parse() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + @parametrize + async def test_streaming_response_update_concurrency(self, async_client: AsyncStructify) -> None: + async with async_client.admin.jobs.with_streaming_response.update_concurrency() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(JobUpdateConcurrencyResponse, job, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/admin/test_teams.py b/tests/api_resources/admin/test_teams.py index 57ba074c1..f1ba06f3b 100644 --- a/tests/api_resources/admin/test_teams.py +++ b/tests/api_resources/admin/test_teams.py @@ -10,13 +10,12 @@ from structify import Structify, AsyncStructify from tests.utils import assert_matches_type from structify._utils import parse_datetime -from structify.pagination import SyncJobsList, AsyncJobsList from structify.types.admin import ( + TeamListResponse, ExtendTrialResponse, ExpireGrantsResponse, GrantCreditsResponse, AdminAddMemberResponse, - AdminTeamsListResponse, AdminListMembersResponse, AdminRemoveMemberResponse, CancelSubscriptionResponse, @@ -33,15 +32,16 @@ class TestTeams: @parametrize def test_method_list(self, client: Structify) -> None: team = client.admin.teams.list() - assert_matches_type(SyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Structify) -> None: team = client.admin.teams.list( limit=0, offset=0, + search="search", ) - assert_matches_type(SyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize def test_raw_response_list(self, client: Structify) -> None: @@ -50,7 +50,7 @@ def test_raw_response_list(self, client: Structify) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" team = response.parse() - assert_matches_type(SyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize def test_streaming_response_list(self, client: Structify) -> None: @@ -59,7 +59,7 @@ def test_streaming_response_list(self, client: Structify) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" team = response.parse() - assert_matches_type(SyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) assert cast(Any, response.is_closed) is True @@ -421,15 +421,16 @@ class TestAsyncTeams: @parametrize async def test_method_list(self, async_client: AsyncStructify) -> None: team = await async_client.admin.teams.list() - assert_matches_type(AsyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncStructify) -> None: team = await async_client.admin.teams.list( limit=0, offset=0, + search="search", ) - assert_matches_type(AsyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncStructify) -> None: @@ -438,7 +439,7 @@ async def test_raw_response_list(self, async_client: AsyncStructify) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" team = await response.parse() - assert_matches_type(AsyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncStructify) -> None: @@ -447,7 +448,7 @@ async def test_streaming_response_list(self, async_client: AsyncStructify) -> No assert response.http_request.headers.get("X-Stainless-Lang") == "python" team = await response.parse() - assert_matches_type(AsyncJobsList[AdminTeamsListResponse], team, path=["response"]) + assert_matches_type(TeamListResponse, team, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/connector_catalog/test_admin.py b/tests/api_resources/connector_catalog/test_admin.py index a4a9898df..10cb267d0 100644 --- a/tests/api_resources/connector_catalog/test_admin.py +++ b/tests/api_resources/connector_catalog/test_admin.py @@ -194,6 +194,8 @@ def test_method_create_catalog_with_all_params(self, client: Structify) -> None: slug="slug", categories=["string"], description="description", + enterprise_only=True, + onboarding_priority=0, priority=0, ) assert_matches_type(ConnectorCatalog, admin, path=["response"]) @@ -558,7 +560,9 @@ def test_method_update_catalog_with_all_params(self, client: Structify) -> None: id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", categories=["string"], description="description", + enterprise_only=True, name="name", + onboarding_priority=0, priority=0, ) assert_matches_type(ConnectorCatalog, admin, path=["response"]) @@ -700,7 +704,7 @@ def test_path_params_update_scope(self, client: Structify) -> None: def test_method_upload_logo(self, client: Structify) -> None: admin = client.connector_catalog.admin.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(UploadLogoResponse, admin, path=["response"]) @@ -708,7 +712,7 @@ def test_method_upload_logo(self, client: Structify) -> None: def test_raw_response_upload_logo(self, client: Structify) -> None: response = client.connector_catalog.admin.with_raw_response.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -720,7 +724,7 @@ def test_raw_response_upload_logo(self, client: Structify) -> None: def test_streaming_response_upload_logo(self, client: Structify) -> None: with client.connector_catalog.admin.with_streaming_response.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -735,7 +739,7 @@ def test_path_params_upload_logo(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `slug` but received ''"): client.connector_catalog.admin.with_raw_response.upload_logo( slug="", - file=b"raw file contents", + file=b"Example data", ) @@ -912,6 +916,8 @@ async def test_method_create_catalog_with_all_params(self, async_client: AsyncSt slug="slug", categories=["string"], description="description", + enterprise_only=True, + onboarding_priority=0, priority=0, ) assert_matches_type(ConnectorCatalog, admin, path=["response"]) @@ -1276,7 +1282,9 @@ async def test_method_update_catalog_with_all_params(self, async_client: AsyncSt id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", categories=["string"], description="description", + enterprise_only=True, name="name", + onboarding_priority=0, priority=0, ) assert_matches_type(ConnectorCatalog, admin, path=["response"]) @@ -1418,7 +1426,7 @@ async def test_path_params_update_scope(self, async_client: AsyncStructify) -> N async def test_method_upload_logo(self, async_client: AsyncStructify) -> None: admin = await async_client.connector_catalog.admin.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(UploadLogoResponse, admin, path=["response"]) @@ -1426,7 +1434,7 @@ async def test_method_upload_logo(self, async_client: AsyncStructify) -> None: async def test_raw_response_upload_logo(self, async_client: AsyncStructify) -> None: response = await async_client.connector_catalog.admin.with_raw_response.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -1438,7 +1446,7 @@ async def test_raw_response_upload_logo(self, async_client: AsyncStructify) -> N async def test_streaming_response_upload_logo(self, async_client: AsyncStructify) -> None: async with async_client.connector_catalog.admin.with_streaming_response.upload_logo( slug="slug", - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1453,5 +1461,5 @@ async def test_path_params_upload_logo(self, async_client: AsyncStructify) -> No with pytest.raises(ValueError, match=r"Expected a non-empty value for `slug` but received ''"): await async_client.connector_catalog.admin.with_raw_response.upload_logo( slug="", - file=b"raw file contents", + file=b"Example data", ) diff --git a/tests/api_resources/test_admin.py b/tests/api_resources/test_admin.py new file mode 100644 index 000000000..2e6c742b9 --- /dev/null +++ b/tests/api_resources/test_admin.py @@ -0,0 +1,84 @@ +# 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 structify import Structify, AsyncStructify + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAdmin: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_report_critical(self, client: Structify) -> None: + admin = client.admin.report_critical( + message="message", + ) + assert admin is None + + @parametrize + def test_raw_response_report_critical(self, client: Structify) -> None: + response = client.admin.with_raw_response.report_critical( + message="message", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin = response.parse() + assert admin is None + + @parametrize + def test_streaming_response_report_critical(self, client: Structify) -> None: + with client.admin.with_streaming_response.report_critical( + message="message", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin = response.parse() + assert admin is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAdmin: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_report_critical(self, async_client: AsyncStructify) -> None: + admin = await async_client.admin.report_critical( + message="message", + ) + assert admin is None + + @parametrize + async def test_raw_response_report_critical(self, async_client: AsyncStructify) -> None: + response = await async_client.admin.with_raw_response.report_critical( + message="message", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + admin = await response.parse() + assert admin is None + + @parametrize + async def test_streaming_response_report_critical(self, async_client: AsyncStructify) -> None: + async with async_client.admin.with_streaming_response.report_critical( + message="message", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + admin = await response.parse() + assert admin is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_chat.py b/tests/api_resources/test_chat.py index 2d1b33db1..c2800d934 100644 --- a/tests/api_resources/test_chat.py +++ b/tests/api_resources/test_chat.py @@ -5,17 +5,21 @@ import os from typing import Any, cast +import httpx import pytest +from respx import MockRouter from structify import Structify, AsyncStructify from tests.utils import assert_matches_type from structify.types import ( - ChatPrompt, ChatSession, + ChatTemplate, + CompressChatResponse, ChatLoadFilesResponse, GetChatSessionResponse, + ListDashboardsResponse, + SimulatePromptResponse, AdminIssueFoundResponse, - ChatDeleteFilesResponse, ChatSessionWithMessages, GetDependenciesResponse, AdminGrantAccessResponse, @@ -27,9 +31,21 @@ CreateChatSessionResponse, DeleteChatSessionResponse, ListCollaboratorsResponse, + ChatListInputFilesResponse, + ChatLoadInputFilesResponse, ChatRevertToCommitResponse, + ChatDeleteInputFileResponse, ChatGetPartialChatsResponse, + ChatUploadInputFileResponse, ChatGetSessionTimelineResponse, + ChatCopyNodeOutputByCodeHashResponse, +) +from structify._utils import parse_datetime +from structify._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -126,44 +142,6 @@ def test_path_params_add_git_commit(self, client: Structify) -> None: commit_hash="commit_hash", ) - @parametrize - def test_method_admin_get_chat_prompt(self, client: Structify) -> None: - chat = client.chat.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - assert_matches_type(ChatPrompt, chat, path=["response"]) - - @parametrize - def test_raw_response_admin_get_chat_prompt(self, client: Structify) -> None: - response = client.chat.with_raw_response.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = response.parse() - assert_matches_type(ChatPrompt, chat, path=["response"]) - - @parametrize - def test_streaming_response_admin_get_chat_prompt(self, client: Structify) -> None: - with client.chat.with_streaming_response.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = response.parse() - assert_matches_type(ChatPrompt, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_admin_get_chat_prompt(self, client: Structify) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): - client.chat.with_raw_response.admin_get_chat_prompt( - "", - ) - @parametrize def test_method_admin_issue_found(self, client: Structify) -> None: chat = client.chat.admin_issue_found( @@ -210,6 +188,44 @@ def test_path_params_admin_issue_found(self, client: Structify) -> None: title="title", ) + @parametrize + def test_method_compress(self, client: Structify) -> None: + chat = client.chat.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_compress(self, client: Structify) -> None: + response = client.chat.with_raw_response.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_compress(self, client: Structify) -> None: + with client.chat.with_streaming_response.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_compress(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.chat.with_raw_response.compress( + "", + ) + @parametrize def test_method_copy(self, client: Structify) -> None: chat = client.chat.copy( @@ -227,6 +243,7 @@ def test_method_copy_with_all_params(self, client: Structify) -> None: team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", copy_inputs=True, project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + template_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ChatSessionWithMessages, chat, path=["response"]) @@ -265,7 +282,7 @@ def test_method_copy_node_output_by_code_hash(self, client: Structify) -> None: code_md5_hash="code_md5_hash", new_node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) @parametrize def test_raw_response_copy_node_output_by_code_hash(self, client: Structify) -> None: @@ -278,7 +295,7 @@ def test_raw_response_copy_node_output_by_code_hash(self, client: Structify) -> assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = response.parse() - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) @parametrize def test_streaming_response_copy_node_output_by_code_hash(self, client: Structify) -> None: @@ -291,7 +308,7 @@ def test_streaming_response_copy_node_output_by_code_hash(self, client: Structif assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = response.parse() - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) assert cast(Any, response.is_closed) is True @@ -323,7 +340,6 @@ def test_method_create_session_with_all_params(self, client: Structify) -> None: "system_prompt": "system_prompt", }, ephemeral=True, - initial_message="initial_message", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(CreateChatSessionResponse, chat, path=["response"]) @@ -353,45 +369,45 @@ def test_streaming_response_create_session(self, client: Structify) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_delete_files(self, client: Structify) -> None: - chat = client.chat.delete_files( + def test_method_delete_input_file(self, client: Structify) -> None: + chat = client.chat.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) @parametrize - def test_raw_response_delete_files(self, client: Structify) -> None: - response = client.chat.with_raw_response.delete_files( + def test_raw_response_delete_input_file(self, client: Structify) -> None: + response = client.chat.with_raw_response.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = response.parse() - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) @parametrize - def test_streaming_response_delete_files(self, client: Structify) -> None: - with client.chat.with_streaming_response.delete_files( + def test_streaming_response_delete_input_file(self, client: Structify) -> None: + with client.chat.with_streaming_response.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = response.parse() - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_delete_files(self, client: Structify) -> None: + def test_path_params_delete_input_file(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chat.with_raw_response.delete_files( + client.chat.with_raw_response.delete_input_file( chat_id="", - paths=["string"], + filenames=["string"], ) @parametrize @@ -632,6 +648,44 @@ def test_path_params_get_session_timeline(self, client: Structify) -> None: "", ) + @parametrize + def test_method_get_template(self, client: Structify) -> None: + chat = client.chat.get_template( + "template_id", + ) + assert_matches_type(ChatTemplate, chat, path=["response"]) + + @parametrize + def test_raw_response_get_template(self, client: Structify) -> None: + response = client.chat.with_raw_response.get_template( + "template_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatTemplate, chat, path=["response"]) + + @parametrize + def test_streaming_response_get_template(self, client: Structify) -> None: + with client.chat.with_streaming_response.get_template( + "template_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatTemplate, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_template(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `template_id` but received ''"): + client.chat.with_raw_response.get_template( + "", + ) + @parametrize def test_method_grant_admin_override(self, client: Structify) -> None: chat = client.chat.grant_admin_override( @@ -716,6 +770,90 @@ def test_path_params_list_collaborators(self, client: Structify) -> None: "", ) + @parametrize + def test_method_list_dashboards(self, client: Structify) -> None: + chat = client.chat.list_dashboards( + chat_id="chat_id", + ) + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + def test_method_list_dashboards_with_all_params(self, client: Structify) -> None: + chat = client.chat.list_dashboards( + chat_id="chat_id", + commit_hash="commit_hash", + ) + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_list_dashboards(self, client: Structify) -> None: + response = client.chat.with_raw_response.list_dashboards( + chat_id="chat_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_list_dashboards(self, client: Structify) -> None: + with client.chat.with_streaming_response.list_dashboards( + chat_id="chat_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_dashboards(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.list_dashboards( + chat_id="", + ) + + @parametrize + def test_method_list_input_files(self, client: Structify) -> None: + chat = client.chat.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_list_input_files(self, client: Structify) -> None: + response = client.chat.with_raw_response.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_list_input_files(self, client: Structify) -> None: + with client.chat.with_streaming_response.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_input_files(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.list_input_files( + "", + ) + @parametrize def test_method_list_sessions(self, client: Structify) -> None: chat = client.chat.list_sessions( @@ -727,8 +865,12 @@ def test_method_list_sessions(self, client: Structify) -> None: def test_method_list_sessions_with_all_params(self, client: Structify) -> None: chat = client.chat.list_sessions( team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=0, + offset=0, project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + search="search", + tab="my_chats", ) assert_matches_type(ListChatSessionsResponse, chat, path=["response"]) @@ -820,6 +962,118 @@ def test_streaming_response_load_files(self, client: Structify) -> None: assert cast(Any, response.is_closed) is True + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_load_input_file(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + chat = client.chat.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert chat.is_closed + assert chat.json() == {"foo": "bar"} + assert cast(Any, chat.is_closed) is True + assert isinstance(chat, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_load_input_file(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + chat = client.chat.with_raw_response.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert chat.is_closed is True + assert chat.http_request.headers.get("X-Stainless-Lang") == "python" + assert chat.json() == {"foo": "bar"} + assert isinstance(chat, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_load_input_file(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + with client.chat.with_streaming_response.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as chat: + assert not chat.is_closed + assert chat.http_request.headers.get("X-Stainless-Lang") == "python" + + assert chat.json() == {"foo": "bar"} + assert cast(Any, chat.is_closed) is True + assert isinstance(chat, StreamedBinaryAPIResponse) + + assert cast(Any, chat.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_load_input_file(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.load_input_file( + filename="filename", + chat_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `filename` but received ''"): + client.chat.with_raw_response.load_input_file( + filename="", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @parametrize + def test_method_load_input_files(self, client: Structify) -> None: + chat = client.chat.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + def test_method_load_input_files_with_all_params(self, client: Structify) -> None: + chat = client.chat.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_load_input_files(self, client: Structify) -> None: + response = client.chat.with_raw_response.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_load_input_files(self, client: Structify) -> None: + with client.chat.with_streaming_response.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_load_input_files(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.load_input_files( + chat_id="", + ) + @parametrize def test_method_make_permanent(self, client: Structify) -> None: chat = client.chat.make_permanent( @@ -948,6 +1202,236 @@ def test_path_params_revert_to_commit(self, client: Structify) -> None: commit_hash="commit_hash", ) + @parametrize + def test_method_simulate_prompt(self, client: Structify) -> None: + chat = client.chat.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_simulate_prompt(self, client: Structify) -> None: + response = client.chat.with_raw_response.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_simulate_prompt(self, client: Structify) -> None: + with client.chat.with_streaming_response.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_simulate_prompt(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_session_id` but received ''"): + client.chat.with_raw_response.simulate_prompt( + chat_session_id="", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + @parametrize def test_method_update_session(self, client: Structify) -> None: chat = client.chat.update_session( @@ -959,6 +1443,7 @@ def test_method_update_session(self, client: Structify) -> None: def test_method_update_session_with_all_params(self, client: Structify) -> None: chat = client.chat.update_session( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + message_head="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", name="name", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", skip_confirmations=True, @@ -1080,6 +1565,56 @@ def test_path_params_update_visibility(self, client: Structify) -> None: visibility="private", ) + @parametrize + def test_method_upload_input_file(self, client: Structify) -> None: + chat = client.chat.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_upload_input_file(self, client: Structify) -> None: + response = client.chat.with_raw_response.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_upload_input_file(self, client: Structify) -> None: + with client.chat.with_streaming_response.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_upload_input_file(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.upload_input_file( + chat_id="", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) + class TestAsyncChat: parametrize = pytest.mark.parametrize( @@ -1174,44 +1709,6 @@ async def test_path_params_add_git_commit(self, async_client: AsyncStructify) -> commit_hash="commit_hash", ) - @parametrize - async def test_method_admin_get_chat_prompt(self, async_client: AsyncStructify) -> None: - chat = await async_client.chat.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - assert_matches_type(ChatPrompt, chat, path=["response"]) - - @parametrize - async def test_raw_response_admin_get_chat_prompt(self, async_client: AsyncStructify) -> None: - response = await async_client.chat.with_raw_response.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = await response.parse() - assert_matches_type(ChatPrompt, chat, path=["response"]) - - @parametrize - async def test_streaming_response_admin_get_chat_prompt(self, async_client: AsyncStructify) -> None: - async with async_client.chat.with_streaming_response.admin_get_chat_prompt( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = await response.parse() - assert_matches_type(ChatPrompt, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_admin_get_chat_prompt(self, async_client: AsyncStructify) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): - await async_client.chat.with_raw_response.admin_get_chat_prompt( - "", - ) - @parametrize async def test_method_admin_issue_found(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.admin_issue_found( @@ -1258,6 +1755,44 @@ async def test_path_params_admin_issue_found(self, async_client: AsyncStructify) title="title", ) + @parametrize + async def test_method_compress(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_compress(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_compress(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.compress( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(CompressChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_compress(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.chat.with_raw_response.compress( + "", + ) + @parametrize async def test_method_copy(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.copy( @@ -1275,6 +1810,7 @@ async def test_method_copy_with_all_params(self, async_client: AsyncStructify) - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", copy_inputs=True, project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + template_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ChatSessionWithMessages, chat, path=["response"]) @@ -1313,7 +1849,7 @@ async def test_method_copy_node_output_by_code_hash(self, async_client: AsyncStr code_md5_hash="code_md5_hash", new_node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) @parametrize async def test_raw_response_copy_node_output_by_code_hash(self, async_client: AsyncStructify) -> None: @@ -1326,7 +1862,7 @@ async def test_raw_response_copy_node_output_by_code_hash(self, async_client: As assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = await response.parse() - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) @parametrize async def test_streaming_response_copy_node_output_by_code_hash(self, async_client: AsyncStructify) -> None: @@ -1339,7 +1875,7 @@ async def test_streaming_response_copy_node_output_by_code_hash(self, async_clie assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = await response.parse() - assert_matches_type(str, chat, path=["response"]) + assert_matches_type(ChatCopyNodeOutputByCodeHashResponse, chat, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1371,7 +1907,6 @@ async def test_method_create_session_with_all_params(self, async_client: AsyncSt "system_prompt": "system_prompt", }, ephemeral=True, - initial_message="initial_message", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(CreateChatSessionResponse, chat, path=["response"]) @@ -1401,45 +1936,45 @@ async def test_streaming_response_create_session(self, async_client: AsyncStruct assert cast(Any, response.is_closed) is True @parametrize - async def test_method_delete_files(self, async_client: AsyncStructify) -> None: - chat = await async_client.chat.delete_files( + async def test_method_delete_input_file(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) @parametrize - async def test_raw_response_delete_files(self, async_client: AsyncStructify) -> None: - response = await async_client.chat.with_raw_response.delete_files( + async def test_raw_response_delete_input_file(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = await response.parse() - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) @parametrize - async def test_streaming_response_delete_files(self, async_client: AsyncStructify) -> None: - async with async_client.chat.with_streaming_response.delete_files( + async def test_streaming_response_delete_input_file(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.delete_input_file( chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - paths=["string"], + filenames=["string"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" chat = await response.parse() - assert_matches_type(ChatDeleteFilesResponse, chat, path=["response"]) + assert_matches_type(ChatDeleteInputFileResponse, chat, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_delete_files(self, async_client: AsyncStructify) -> None: + async def test_path_params_delete_input_file(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chat.with_raw_response.delete_files( + await async_client.chat.with_raw_response.delete_input_file( chat_id="", - paths=["string"], + filenames=["string"], ) @parametrize @@ -1680,6 +2215,44 @@ async def test_path_params_get_session_timeline(self, async_client: AsyncStructi "", ) + @parametrize + async def test_method_get_template(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.get_template( + "template_id", + ) + assert_matches_type(ChatTemplate, chat, path=["response"]) + + @parametrize + async def test_raw_response_get_template(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.get_template( + "template_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatTemplate, chat, path=["response"]) + + @parametrize + async def test_streaming_response_get_template(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.get_template( + "template_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatTemplate, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_template(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `template_id` but received ''"): + await async_client.chat.with_raw_response.get_template( + "", + ) + @parametrize async def test_method_grant_admin_override(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.grant_admin_override( @@ -1764,6 +2337,90 @@ async def test_path_params_list_collaborators(self, async_client: AsyncStructify "", ) + @parametrize + async def test_method_list_dashboards(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.list_dashboards( + chat_id="chat_id", + ) + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + async def test_method_list_dashboards_with_all_params(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.list_dashboards( + chat_id="chat_id", + commit_hash="commit_hash", + ) + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_list_dashboards(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.list_dashboards( + chat_id="chat_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_list_dashboards(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.list_dashboards( + chat_id="chat_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ListDashboardsResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_dashboards(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.list_dashboards( + chat_id="", + ) + + @parametrize + async def test_method_list_input_files(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_list_input_files(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_list_input_files(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.list_input_files( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatListInputFilesResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_input_files(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.list_input_files( + "", + ) + @parametrize async def test_method_list_sessions(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.list_sessions( @@ -1775,8 +2432,12 @@ async def test_method_list_sessions(self, async_client: AsyncStructify) -> None: async def test_method_list_sessions_with_all_params(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.list_sessions( team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=0, + offset=0, project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + search="search", + tab="my_chats", ) assert_matches_type(ListChatSessionsResponse, chat, path=["response"]) @@ -1868,6 +2529,120 @@ async def test_streaming_response_load_files(self, async_client: AsyncStructify) assert cast(Any, response.is_closed) is True + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_load_input_file(self, async_client: AsyncStructify, respx_mock: MockRouter) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + chat = await async_client.chat.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert chat.is_closed + assert await chat.json() == {"foo": "bar"} + assert cast(Any, chat.is_closed) is True + assert isinstance(chat, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_load_input_file(self, async_client: AsyncStructify, respx_mock: MockRouter) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + chat = await async_client.chat.with_raw_response.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert chat.is_closed is True + assert chat.http_request.headers.get("X-Stainless-Lang") == "python" + assert await chat.json() == {"foo": "bar"} + assert isinstance(chat, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_load_input_file( + self, async_client: AsyncStructify, respx_mock: MockRouter + ) -> None: + respx_mock.get("/chat/input-files/download/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/filename").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + async with async_client.chat.with_streaming_response.load_input_file( + filename="filename", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as chat: + assert not chat.is_closed + assert chat.http_request.headers.get("X-Stainless-Lang") == "python" + + assert await chat.json() == {"foo": "bar"} + assert cast(Any, chat.is_closed) is True + assert isinstance(chat, AsyncStreamedBinaryAPIResponse) + + assert cast(Any, chat.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_load_input_file(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.load_input_file( + filename="filename", + chat_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `filename` but received ''"): + await async_client.chat.with_raw_response.load_input_file( + filename="", + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @parametrize + async def test_method_load_input_files(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + async def test_method_load_input_files_with_all_params(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_load_input_files(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_load_input_files(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.load_input_files( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatLoadInputFilesResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_load_input_files(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.load_input_files( + chat_id="", + ) + @parametrize async def test_method_make_permanent(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.make_permanent( @@ -1996,6 +2771,236 @@ async def test_path_params_revert_to_commit(self, async_client: AsyncStructify) commit_hash="commit_hash", ) + @parametrize + async def test_method_simulate_prompt(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_simulate_prompt(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_simulate_prompt(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.simulate_prompt( + chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(SimulatePromptResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_simulate_prompt(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_session_id` but received ''"): + await async_client.chat.with_raw_response.simulate_prompt( + chat_session_id="", + chat_prompt={ + "decoding_params": {"parameters": [{"max_tokens": 0}]}, + "messages": [ + { + "content": [{"text": "Text"}], + "role": "user", + } + ], + "metadata": { + "dataset_descriptor": { + "description": "description", + "name": "name", + "relationships": [ + { + "description": "description", + "name": "name", + "source_table": "source_table", + "target_table": "target_table", + } + ], + "tables": [ + { + "description": "description", + "name": "name", + "properties": [ + { + "description": "description", + "name": "name", + } + ], + } + ], + }, + "extracted_entities": [ + { + "entities": [ + { + "id": 0, + "properties": {"foo": "string"}, + "type": "type", + } + ] + } + ], + "extraction_criteria": [{"relationship_name": "relationship_name"}], + "formatter_specific": {"image_meta": {"image": "image"}}, + }, + }, + ) + @parametrize async def test_method_update_session(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.update_session( @@ -2007,6 +3012,7 @@ async def test_method_update_session(self, async_client: AsyncStructify) -> None async def test_method_update_session_with_all_params(self, async_client: AsyncStructify) -> None: chat = await async_client.chat.update_session( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + message_head="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", name="name", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", skip_confirmations=True, @@ -2127,3 +3133,53 @@ async def test_path_params_update_visibility(self, async_client: AsyncStructify) session_id="", visibility="private", ) + + @parametrize + async def test_method_upload_input_file(self, async_client: AsyncStructify) -> None: + chat = await async_client.chat.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_upload_input_file(self, async_client: AsyncStructify) -> None: + response = await async_client.chat.with_raw_response.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_upload_input_file(self, async_client: AsyncStructify) -> None: + async with async_client.chat.with_streaming_response.upload_input_file( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatUploadInputFileResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_upload_input_file(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.upload_input_file( + chat_id="", + content=b"Example data", + content_type="content_type", + file_name="file_name", + ) diff --git a/tests/api_resources/test_code.py b/tests/api_resources/test_code.py index ae45f5a7d..ee3fd18c4 100644 --- a/tests/api_resources/test_code.py +++ b/tests/api_resources/test_code.py @@ -15,6 +15,52 @@ class TestCode: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_apply_manual_edit(self, client: Structify) -> None: + code = client.code.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) + assert code is None + + @parametrize + def test_raw_response_apply_manual_edit(self, client: Structify) -> None: + response = client.code.with_raw_response.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + code = response.parse() + assert code is None + + @parametrize + def test_streaming_response_apply_manual_edit(self, client: Structify) -> None: + with client.code.with_streaming_response.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + code = response.parse() + assert code is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_apply_manual_edit(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.code.with_raw_response.apply_manual_edit( + chat_id="", + code="code", + filename="filename", + ) + @parametrize def test_method_generate_code(self, client: Structify) -> None: code = client.code.generate_code( @@ -107,6 +153,52 @@ class TestAsyncCode: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @parametrize + async def test_method_apply_manual_edit(self, async_client: AsyncStructify) -> None: + code = await async_client.code.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) + assert code is None + + @parametrize + async def test_raw_response_apply_manual_edit(self, async_client: AsyncStructify) -> None: + response = await async_client.code.with_raw_response.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + code = await response.parse() + assert code is None + + @parametrize + async def test_streaming_response_apply_manual_edit(self, async_client: AsyncStructify) -> None: + async with async_client.code.with_streaming_response.apply_manual_edit( + chat_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + code="code", + filename="filename", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + code = await response.parse() + assert code is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_apply_manual_edit(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.code.with_raw_response.apply_manual_edit( + chat_id="", + code="code", + filename="filename", + ) + @parametrize async def test_method_generate_code(self, async_client: AsyncStructify) -> None: code = await async_client.code.generate_code( diff --git a/tests/api_resources/test_connector_catalog.py b/tests/api_resources/test_connector_catalog.py index 632fe5174..bae5c1420 100644 --- a/tests/api_resources/test_connector_catalog.py +++ b/tests/api_resources/test_connector_catalog.py @@ -33,6 +33,7 @@ def test_method_list(self, client: Structify) -> None: @parametrize def test_method_list_with_all_params(self, client: Structify) -> None: connector_catalog = client.connector_catalog.list( + categories=["string"], include_inactive=True, limit=0, offset=0, @@ -162,6 +163,7 @@ async def test_method_list(self, async_client: AsyncStructify) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncStructify) -> None: connector_catalog = await async_client.connector_catalog.list( + categories=["string"], include_inactive=True, limit=0, offset=0, diff --git a/tests/api_resources/test_connectors.py b/tests/api_resources/test_connectors.py index c1cd9fe39..138becde0 100644 --- a/tests/api_resources/test_connectors.py +++ b/tests/api_resources/test_connectors.py @@ -3,29 +3,41 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast +import httpx import pytest +from respx import MockRouter from structify import Structify, AsyncStructify from tests.utils import assert_matches_type from structify.types import ( Connector, + ExplorationRun, ListTablesResponse, + ExplorationProgress, UpdateTableResponse, ConnectorGetResponse, ConnectorWithSecrets, ExplorerChatResponse, - ExploreStatusResponse, ConnectorStoreResponse, ExplorationRunsResponse, + ConnectorExploreResponse, ConnectorSummariesResponse, + ConnectorTablePathResponse, DeleteSchemaObjectResponse, + ConnectorListStoresResponse, ConnectorSearchTablesResponse, ConnectorAddSchemaObjectResponse, ConnectorListWithSnippetsResponse, ConnectorGetClarificationRequestsResponse, ) +from structify._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, +) from structify.pagination import SyncJobsList, AsyncJobsList base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -39,7 +51,6 @@ def test_method_create(self, client: Structify) -> None: connector = client.connectors.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(Connector, connector, path=["response"]) @@ -48,14 +59,8 @@ def test_method_create_with_all_params(self, client: Structify) -> None: connector = client.connectors.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", description="description", nango_connection_id="nango_connection_id", - nango_integration_id="nango_integration_id", - pipedream_account_id="pipedream_account_id", - pipedream_external_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - pipedream_project_id="pipedream_project_id", - refresh_script="refresh_script", secrets={"foo": "string"}, ) assert_matches_type(Connector, connector, path=["response"]) @@ -65,7 +70,6 @@ def test_raw_response_create(self, client: Structify) -> None: response = client.connectors.with_raw_response.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -78,7 +82,6 @@ def test_streaming_response_create(self, client: Structify) -> None: with client.connectors.with_streaming_response.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -99,11 +102,20 @@ def test_method_update(self, client: Structify) -> None: def test_method_update_with_all_params(self, client: Structify) -> None: connector = client.connectors.update( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_category="RelationalDatabase", + datahub_ingestion_type="datahub_ingestion_type", + datahub_secret_map={"foo": "string"}, + datahub_urn="datahub_urn", description="description", known_connector_type="known_connector_type", name="name", - refresh_script="refresh_script", + nango_connection_id="nango_connection_id", + oauth_scopes=["string"], + owner_user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + refresh_cron_schedule="refresh_cron_schedule", + team_visibility="Team", usage_snippet_override="usage_snippet_override", + user_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert connector is None @@ -140,15 +152,12 @@ def test_path_params_update(self, client: Structify) -> None: @parametrize def test_method_list(self, client: Structify) -> None: - connector = client.connectors.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + connector = client.connectors.list() assert_matches_type(SyncJobsList[ConnectorWithSecrets], connector, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Structify) -> None: connector = client.connectors.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=0, offset=0, ) @@ -156,9 +165,7 @@ def test_method_list_with_all_params(self, client: Structify) -> None: @parametrize def test_raw_response_list(self, client: Structify) -> None: - response = client.connectors.with_raw_response.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + response = client.connectors.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -167,9 +174,7 @@ def test_raw_response_list(self, client: Structify) -> None: @parametrize def test_streaming_response_list(self, client: Structify) -> None: - with client.connectors.with_streaming_response.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: + with client.connectors.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -742,23 +747,105 @@ def test_path_params_delete_secret(self, client: Structify) -> None: connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download_datahub_artifact(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + connector = client.connectors.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert connector.is_closed + assert connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_download_datahub_artifact_with_all_params(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + connector = client.connectors.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert connector.is_closed + assert connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_download_datahub_artifact(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + connector = client.connectors.with_raw_response.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert connector.is_closed is True + assert connector.http_request.headers.get("X-Stainless-Lang") == "python" + assert connector.json() == {"foo": "bar"} + assert isinstance(connector, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_download_datahub_artifact(self, client: Structify, respx_mock: MockRouter) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + with client.connectors.with_streaming_response.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as connector: + assert not connector.is_closed + assert connector.http_request.headers.get("X-Stainless-Lang") == "python" + + assert connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, StreamedBinaryAPIResponse) + + assert cast(Any, connector.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_download_datahub_artifact(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + client.connectors.with_raw_response.download_datahub_artifact( + kind="kind", + connector_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `kind` but received ''"): + client.connectors.with_raw_response.download_datahub_artifact( + kind="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + @parametrize def test_method_explore(self, client: Structify) -> None: connector = client.connectors.explore( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize def test_method_explore_with_all_params(self, client: Structify) -> None: connector = client.connectors.explore( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", database_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + only_do_datahub=True, schema_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - stage="both", table_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize def test_raw_response_explore(self, client: Structify) -> None: @@ -769,7 +856,7 @@ def test_raw_response_explore(self, client: Structify) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize def test_streaming_response_explore(self, client: Structify) -> None: @@ -780,7 +867,7 @@ def test_streaming_response_explore(self, client: Structify) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) assert cast(Any, response.is_closed) is True @@ -829,6 +916,44 @@ def test_path_params_get(self, client: Structify) -> None: "", ) + @parametrize + def test_method_get_active_exploration_run(self, client: Structify) -> None: + connector = client.connectors.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + @parametrize + def test_raw_response_get_active_exploration_run(self, client: Structify) -> None: + response = client.connectors.with_raw_response.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + @parametrize + def test_streaming_response_get_active_exploration_run(self, client: Structify) -> None: + with client.connectors.with_streaming_response.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_active_exploration_run(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + client.connectors.with_raw_response.get_active_exploration_run( + "", + ) + @parametrize def test_method_get_clarification_requests(self, client: Structify) -> None: connector = client.connectors.get_clarification_requests( @@ -868,78 +993,88 @@ def test_path_params_get_clarification_requests(self, client: Structify) -> None ) @parametrize - def test_method_get_exploration_runs(self, client: Structify) -> None: - connector = client.connectors.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + def test_method_get_exploration_run_progress(self, client: Structify) -> None: + connector = client.connectors.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) @parametrize - def test_raw_response_get_exploration_runs(self, client: Structify) -> None: - response = client.connectors.with_raw_response.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + def test_raw_response_get_exploration_run_progress(self, client: Structify) -> None: + response = client.connectors.with_raw_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) @parametrize - def test_streaming_response_get_exploration_runs(self, client: Structify) -> None: - with client.connectors.with_streaming_response.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + def test_streaming_response_get_exploration_run_progress(self, client: Structify) -> None: + with client.connectors.with_streaming_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_exploration_runs(self, client: Structify) -> None: + def test_path_params_get_exploration_run_progress(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): - client.connectors.with_raw_response.get_exploration_runs( - "", + client.connectors.with_raw_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + client.connectors.with_raw_response.get_exploration_run_progress( + run_id="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) @parametrize - def test_method_get_exploration_status(self, client: Structify) -> None: - connector = client.connectors.get_exploration_status( + def test_method_get_exploration_runs(self, client: Structify) -> None: + connector = client.connectors.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) @parametrize - def test_raw_response_get_exploration_status(self, client: Structify) -> None: - response = client.connectors.with_raw_response.get_exploration_status( + def test_raw_response_get_exploration_runs(self, client: Structify) -> None: + response = client.connectors.with_raw_response.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) @parametrize - def test_streaming_response_get_exploration_status(self, client: Structify) -> None: - with client.connectors.with_streaming_response.get_exploration_status( + def test_streaming_response_get_exploration_runs(self, client: Structify) -> None: + with client.connectors.with_streaming_response.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = response.parse() - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_exploration_status(self, client: Structify) -> None: + def test_path_params_get_exploration_runs(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): - client.connectors.with_raw_response.get_exploration_status( + client.connectors.with_raw_response.get_exploration_runs( "", ) @@ -947,7 +1082,17 @@ def test_path_params_get_exploration_status(self, client: Structify) -> None: def test_method_get_explorer_chat(self, client: Structify) -> None: connector = client.connectors.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", + ) + assert_matches_type(ExplorerChatResponse, connector, path=["response"]) + + @parametrize + def test_method_get_explorer_chat_with_all_params(self, client: Structify) -> None: + connector = client.connectors.get_explorer_chat( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + database_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + schema_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + table_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ExplorerChatResponse, connector, path=["response"]) @@ -955,7 +1100,6 @@ def test_method_get_explorer_chat(self, client: Structify) -> None: def test_raw_response_get_explorer_chat(self, client: Structify) -> None: response = client.connectors.with_raw_response.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", ) assert response.is_closed is True @@ -967,7 +1111,6 @@ def test_raw_response_get_explorer_chat(self, client: Structify) -> None: def test_streaming_response_get_explorer_chat(self, client: Structify) -> None: with client.connectors.with_streaming_response.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -982,7 +1125,6 @@ def test_path_params_get_explorer_chat(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): client.connectors.with_raw_response.get_explorer_chat( connector_id="", - run_id="run_id", ) @parametrize @@ -1023,6 +1165,69 @@ def test_path_params_get_store(self, client: Structify) -> None: "", ) + @parametrize + def test_method_get_table_path(self, client: Structify) -> None: + connector = client.connectors.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + @parametrize + def test_raw_response_get_table_path(self, client: Structify) -> None: + response = client.connectors.with_raw_response.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + @parametrize + def test_streaming_response_get_table_path(self, client: Structify) -> None: + with client.connectors.with_streaming_response.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_table_path(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `table_id` but received ''"): + client.connectors.with_raw_response.get_table_path( + "", + ) + + @parametrize + def test_method_list_stores(self, client: Structify) -> None: + connector = client.connectors.list_stores() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + @parametrize + def test_raw_response_list_stores(self, client: Structify) -> None: + response = client.connectors.with_raw_response.list_stores() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + @parametrize + def test_streaming_response_list_stores(self, client: Structify) -> None: + with client.connectors.with_streaming_response.list_stores() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list_tables(self, client: Structify) -> None: connector = client.connectors.list_tables( @@ -1063,16 +1268,12 @@ def test_path_params_list_tables(self, client: Structify) -> None: @parametrize def test_method_list_with_snippets(self, client: Structify) -> None: - connector = client.connectors.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + connector = client.connectors.list_with_snippets() assert_matches_type(ConnectorListWithSnippetsResponse, connector, path=["response"]) @parametrize def test_raw_response_list_with_snippets(self, client: Structify) -> None: - response = client.connectors.with_raw_response.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + response = client.connectors.with_raw_response.list_with_snippets() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1081,9 +1282,7 @@ def test_raw_response_list_with_snippets(self, client: Structify) -> None: @parametrize def test_streaming_response_list_with_snippets(self, client: Structify) -> None: - with client.connectors.with_streaming_response.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: + with client.connectors.with_streaming_response.list_with_snippets() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1168,7 +1367,6 @@ def test_streaming_response_search_tables(self, client: Structify) -> None: def test_method_summaries(self, client: Structify) -> None: connector = client.connectors.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ConnectorSummariesResponse, connector, path=["response"]) @@ -1176,7 +1374,6 @@ def test_method_summaries(self, client: Structify) -> None: def test_raw_response_summaries(self, client: Structify) -> None: response = client.connectors.with_raw_response.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -1188,7 +1385,6 @@ def test_raw_response_summaries(self, client: Structify) -> None: def test_streaming_response_summaries(self, client: Structify) -> None: with client.connectors.with_streaming_response.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1291,6 +1487,64 @@ def test_path_params_update_table(self, client: Structify) -> None: table_id="", ) + @parametrize + def test_method_upload_datahub_artifact(self, client: Structify) -> None: + connector = client.connectors.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + assert connector is None + + @parametrize + def test_raw_response_upload_datahub_artifact(self, client: Structify) -> None: + response = client.connectors.with_raw_response.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = response.parse() + assert connector is None + + @parametrize + def test_streaming_response_upload_datahub_artifact(self, client: Structify) -> None: + with client.connectors.with_streaming_response.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = response.parse() + assert connector is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_upload_datahub_artifact(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + client.connectors.with_raw_response.upload_datahub_artifact( + kind="kind", + connector_id="", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `kind` but received ''"): + client.connectors.with_raw_response.upload_datahub_artifact( + kind="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + class TestAsyncConnectors: parametrize = pytest.mark.parametrize( @@ -1302,7 +1556,6 @@ async def test_method_create(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(Connector, connector, path=["response"]) @@ -1311,14 +1564,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncStructify) connector = await async_client.connectors.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", description="description", nango_connection_id="nango_connection_id", - nango_integration_id="nango_integration_id", - pipedream_account_id="pipedream_account_id", - pipedream_external_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - pipedream_project_id="pipedream_project_id", - refresh_script="refresh_script", secrets={"foo": "string"}, ) assert_matches_type(Connector, connector, path=["response"]) @@ -1328,7 +1575,6 @@ async def test_raw_response_create(self, async_client: AsyncStructify) -> None: response = await async_client.connectors.with_raw_response.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -1341,7 +1587,6 @@ async def test_streaming_response_create(self, async_client: AsyncStructify) -> async with async_client.connectors.with_streaming_response.create( known_connector_type="known_connector_type", name="name", - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1362,11 +1607,20 @@ async def test_method_update(self, async_client: AsyncStructify) -> None: async def test_method_update_with_all_params(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.update( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_category="RelationalDatabase", + datahub_ingestion_type="datahub_ingestion_type", + datahub_secret_map={"foo": "string"}, + datahub_urn="datahub_urn", description="description", known_connector_type="known_connector_type", name="name", - refresh_script="refresh_script", + nango_connection_id="nango_connection_id", + oauth_scopes=["string"], + owner_user_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + refresh_cron_schedule="refresh_cron_schedule", + team_visibility="Team", usage_snippet_override="usage_snippet_override", + user_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert connector is None @@ -1403,15 +1657,12 @@ async def test_path_params_update(self, async_client: AsyncStructify) -> None: @parametrize async def test_method_list(self, async_client: AsyncStructify) -> None: - connector = await async_client.connectors.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + connector = await async_client.connectors.list() assert_matches_type(AsyncJobsList[ConnectorWithSecrets], connector, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=0, offset=0, ) @@ -1419,9 +1670,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncStructify) - @parametrize async def test_raw_response_list(self, async_client: AsyncStructify) -> None: - response = await async_client.connectors.with_raw_response.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + response = await async_client.connectors.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1430,9 +1679,7 @@ async def test_raw_response_list(self, async_client: AsyncStructify) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncStructify) -> None: - async with async_client.connectors.with_streaming_response.list( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: + async with async_client.connectors.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2005,23 +2252,111 @@ async def test_path_params_delete_secret(self, async_client: AsyncStructify) -> connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download_datahub_artifact(self, async_client: AsyncStructify, respx_mock: MockRouter) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + connector = await async_client.connectors.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert connector.is_closed + assert await connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_download_datahub_artifact_with_all_params( + self, async_client: AsyncStructify, respx_mock: MockRouter + ) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + connector = await async_client.connectors.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert connector.is_closed + assert await connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_download_datahub_artifact( + self, async_client: AsyncStructify, respx_mock: MockRouter + ) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + + connector = await async_client.connectors.with_raw_response.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert connector.is_closed is True + assert connector.http_request.headers.get("X-Stainless-Lang") == "python" + assert await connector.json() == {"foo": "bar"} + assert isinstance(connector, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_download_datahub_artifact( + self, async_client: AsyncStructify, respx_mock: MockRouter + ) -> None: + respx_mock.get("/internal/connectors/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e/datahub-artifacts/kind").mock( + return_value=httpx.Response(200, json={"foo": "bar"}) + ) + async with async_client.connectors.with_streaming_response.download_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as connector: + assert not connector.is_closed + assert connector.http_request.headers.get("X-Stainless-Lang") == "python" + + assert await connector.json() == {"foo": "bar"} + assert cast(Any, connector.is_closed) is True + assert isinstance(connector, AsyncStreamedBinaryAPIResponse) + + assert cast(Any, connector.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_download_datahub_artifact(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + await async_client.connectors.with_raw_response.download_datahub_artifact( + kind="kind", + connector_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `kind` but received ''"): + await async_client.connectors.with_raw_response.download_datahub_artifact( + kind="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + @parametrize async def test_method_explore(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.explore( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize async def test_method_explore_with_all_params(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.explore( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", database_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + only_do_datahub=True, schema_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - stage="both", table_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize async def test_raw_response_explore(self, async_client: AsyncStructify) -> None: @@ -2032,7 +2367,7 @@ async def test_raw_response_explore(self, async_client: AsyncStructify) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) @parametrize async def test_streaming_response_explore(self, async_client: AsyncStructify) -> None: @@ -2043,7 +2378,7 @@ async def test_streaming_response_explore(self, async_client: AsyncStructify) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert connector is None + assert_matches_type(ConnectorExploreResponse, connector, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2092,6 +2427,44 @@ async def test_path_params_get(self, async_client: AsyncStructify) -> None: "", ) + @parametrize + async def test_method_get_active_exploration_run(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + @parametrize + async def test_raw_response_get_active_exploration_run(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + @parametrize + async def test_streaming_response_get_active_exploration_run(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.get_active_exploration_run( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert_matches_type(Optional[ExplorationRun], connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_active_exploration_run(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + await async_client.connectors.with_raw_response.get_active_exploration_run( + "", + ) + @parametrize async def test_method_get_clarification_requests(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.get_clarification_requests( @@ -2131,78 +2504,88 @@ async def test_path_params_get_clarification_requests(self, async_client: AsyncS ) @parametrize - async def test_method_get_exploration_runs(self, async_client: AsyncStructify) -> None: - connector = await async_client.connectors.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + async def test_method_get_exploration_run_progress(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) @parametrize - async def test_raw_response_get_exploration_runs(self, async_client: AsyncStructify) -> None: - response = await async_client.connectors.with_raw_response.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + async def test_raw_response_get_exploration_run_progress(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) @parametrize - async def test_streaming_response_get_exploration_runs(self, async_client: AsyncStructify) -> None: - async with async_client.connectors.with_streaming_response.get_exploration_runs( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + async def test_streaming_response_get_exploration_run_progress(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) + assert_matches_type(ExplorationProgress, connector, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_exploration_runs(self, async_client: AsyncStructify) -> None: + async def test_path_params_get_exploration_run_progress(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): - await async_client.connectors.with_raw_response.get_exploration_runs( - "", + await async_client.connectors.with_raw_response.get_exploration_run_progress( + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + connector_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `run_id` but received ''"): + await async_client.connectors.with_raw_response.get_exploration_run_progress( + run_id="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) @parametrize - async def test_method_get_exploration_status(self, async_client: AsyncStructify) -> None: - connector = await async_client.connectors.get_exploration_status( + async def test_method_get_exploration_runs(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) @parametrize - async def test_raw_response_get_exploration_status(self, async_client: AsyncStructify) -> None: - response = await async_client.connectors.with_raw_response.get_exploration_status( + async def test_raw_response_get_exploration_runs(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) @parametrize - async def test_streaming_response_get_exploration_status(self, async_client: AsyncStructify) -> None: - async with async_client.connectors.with_streaming_response.get_exploration_status( + async def test_streaming_response_get_exploration_runs(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.get_exploration_runs( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" connector = await response.parse() - assert_matches_type(ExploreStatusResponse, connector, path=["response"]) + assert_matches_type(ExplorationRunsResponse, connector, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_exploration_status(self, async_client: AsyncStructify) -> None: + async def test_path_params_get_exploration_runs(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): - await async_client.connectors.with_raw_response.get_exploration_status( + await async_client.connectors.with_raw_response.get_exploration_runs( "", ) @@ -2210,7 +2593,17 @@ async def test_path_params_get_exploration_status(self, async_client: AsyncStruc async def test_method_get_explorer_chat(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", + ) + assert_matches_type(ExplorerChatResponse, connector, path=["response"]) + + @parametrize + async def test_method_get_explorer_chat_with_all_params(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.get_explorer_chat( + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + database_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + schema_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + table_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ExplorerChatResponse, connector, path=["response"]) @@ -2218,7 +2611,6 @@ async def test_method_get_explorer_chat(self, async_client: AsyncStructify) -> N async def test_raw_response_get_explorer_chat(self, async_client: AsyncStructify) -> None: response = await async_client.connectors.with_raw_response.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", ) assert response.is_closed is True @@ -2230,7 +2622,6 @@ async def test_raw_response_get_explorer_chat(self, async_client: AsyncStructify async def test_streaming_response_get_explorer_chat(self, async_client: AsyncStructify) -> None: async with async_client.connectors.with_streaming_response.get_explorer_chat( connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - run_id="run_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2245,7 +2636,6 @@ async def test_path_params_get_explorer_chat(self, async_client: AsyncStructify) with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): await async_client.connectors.with_raw_response.get_explorer_chat( connector_id="", - run_id="run_id", ) @parametrize @@ -2286,6 +2676,69 @@ async def test_path_params_get_store(self, async_client: AsyncStructify) -> None "", ) + @parametrize + async def test_method_get_table_path(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + @parametrize + async def test_raw_response_get_table_path(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + @parametrize + async def test_streaming_response_get_table_path(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.get_table_path( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert_matches_type(ConnectorTablePathResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_table_path(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `table_id` but received ''"): + await async_client.connectors.with_raw_response.get_table_path( + "", + ) + + @parametrize + async def test_method_list_stores(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.list_stores() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + @parametrize + async def test_raw_response_list_stores(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.list_stores() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + @parametrize + async def test_streaming_response_list_stores(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.list_stores() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert_matches_type(ConnectorListStoresResponse, connector, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list_tables(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.list_tables( @@ -2326,16 +2779,12 @@ async def test_path_params_list_tables(self, async_client: AsyncStructify) -> No @parametrize async def test_method_list_with_snippets(self, async_client: AsyncStructify) -> None: - connector = await async_client.connectors.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + connector = await async_client.connectors.list_with_snippets() assert_matches_type(ConnectorListWithSnippetsResponse, connector, path=["response"]) @parametrize async def test_raw_response_list_with_snippets(self, async_client: AsyncStructify) -> None: - response = await async_client.connectors.with_raw_response.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) + response = await async_client.connectors.with_raw_response.list_with_snippets() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2344,9 +2793,7 @@ async def test_raw_response_list_with_snippets(self, async_client: AsyncStructif @parametrize async def test_streaming_response_list_with_snippets(self, async_client: AsyncStructify) -> None: - async with async_client.connectors.with_streaming_response.list_with_snippets( - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: + async with async_client.connectors.with_streaming_response.list_with_snippets() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2431,7 +2878,6 @@ async def test_streaming_response_search_tables(self, async_client: AsyncStructi async def test_method_summaries(self, async_client: AsyncStructify) -> None: connector = await async_client.connectors.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ConnectorSummariesResponse, connector, path=["response"]) @@ -2439,7 +2885,6 @@ async def test_method_summaries(self, async_client: AsyncStructify) -> None: async def test_raw_response_summaries(self, async_client: AsyncStructify) -> None: response = await async_client.connectors.with_raw_response.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -2451,7 +2896,6 @@ async def test_raw_response_summaries(self, async_client: AsyncStructify) -> Non async def test_streaming_response_summaries(self, async_client: AsyncStructify) -> None: async with async_client.connectors.with_streaming_response.summaries( connector_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2553,3 +2997,61 @@ async def test_path_params_update_table(self, async_client: AsyncStructify) -> N await async_client.connectors.with_raw_response.update_table( table_id="", ) + + @parametrize + async def test_method_upload_datahub_artifact(self, async_client: AsyncStructify) -> None: + connector = await async_client.connectors.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + assert connector is None + + @parametrize + async def test_raw_response_upload_datahub_artifact(self, async_client: AsyncStructify) -> None: + response = await async_client.connectors.with_raw_response.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connector = await response.parse() + assert connector is None + + @parametrize + async def test_streaming_response_upload_datahub_artifact(self, async_client: AsyncStructify) -> None: + async with async_client.connectors.with_streaming_response.upload_datahub_artifact( + kind="kind", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connector = await response.parse() + assert connector is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_upload_datahub_artifact(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `connector_id` but received ''"): + await async_client.connectors.with_raw_response.upload_datahub_artifact( + kind="kind", + connector_id="", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `kind` but received ''"): + await async_client.connectors.with_raw_response.upload_datahub_artifact( + kind="", + connector_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + exploration_run_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + file=b"Example data", + ) diff --git a/tests/api_resources/test_dataframe.py b/tests/api_resources/test_dataframe.py index 89b13a0f3..2b90d2fb4 100644 --- a/tests/api_resources/test_dataframe.py +++ b/tests/api_resources/test_dataframe.py @@ -115,9 +115,9 @@ def test_method_enhance_relationships(self, client: Structify) -> None: mock_source_3 = Mock(id="entity-3", properties={"company_name": "Microsoft"}) # Target/connected entities - mock_target_1 = Mock(id="target-1", properties={"employee_name": "Alex", "position": "CEO"}, job_ids=["job-1"]) - mock_target_2 = Mock(id="target-2", properties={"employee_name": "Alex", "position": "SWE"}, job_ids=["job-2"]) - mock_target_3 = Mock(id="target-3", properties={"employee_name": "Alex", "position": "PM"}, job_ids=["job-3"]) + mock_target_1 = Mock(id="target-1", properties={"employee_name": "Alex", "position": "CEO"}, job_id="job-1") + mock_target_2 = Mock(id="target-2", properties={"employee_name": "Alex", "position": "SWE"}, job_id="job-2") + mock_target_3 = Mock(id="target-3", properties={"employee_name": "Alex", "position": "PM"}, job_id="job-3") # Relationships connecting sources to targets rel1 = Mock(from_id="entity-1", to_id="target-1") diff --git a/tests/api_resources/test_documents.py b/tests/api_resources/test_documents.py index 0882dfaf9..6562d8463 100644 --- a/tests/api_resources/test_documents.py +++ b/tests/api_resources/test_documents.py @@ -118,18 +118,18 @@ def test_streaming_response_download(self, client: Structify) -> None: @parametrize def test_method_upload(self, client: Structify) -> None: document = client.documents.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) assert document is None @parametrize def test_method_upload_with_all_params(self, client: Structify) -> None: document = client.documents.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", dataset="dataset", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) @@ -138,9 +138,9 @@ def test_method_upload_with_all_params(self, client: Structify) -> None: @parametrize def test_raw_response_upload(self, client: Structify) -> None: response = client.documents.with_raw_response.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) assert response.is_closed is True @@ -151,9 +151,9 @@ def test_raw_response_upload(self, client: Structify) -> None: @parametrize def test_streaming_response_upload(self, client: Structify) -> None: with client.documents.with_streaming_response.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -267,18 +267,18 @@ async def test_streaming_response_download(self, async_client: AsyncStructify) - @parametrize async def test_method_upload(self, async_client: AsyncStructify) -> None: document = await async_client.documents.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) assert document is None @parametrize async def test_method_upload_with_all_params(self, async_client: AsyncStructify) -> None: document = await async_client.documents.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", dataset="dataset", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) @@ -287,9 +287,9 @@ async def test_method_upload_with_all_params(self, async_client: AsyncStructify) @parametrize async def test_raw_response_upload(self, async_client: AsyncStructify) -> None: response = await async_client.documents.with_raw_response.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) assert response.is_closed is True @@ -300,9 +300,9 @@ async def test_raw_response_upload(self, async_client: AsyncStructify) -> None: @parametrize async def test_streaming_response_upload(self, async_client: AsyncStructify) -> None: async with async_client.documents.with_streaming_response.upload( - content=b"raw file contents", + content=b"Example data", file_type="Text", - path=b"raw file contents", + path=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_entities.py b/tests/api_resources/test_entities.py index 0e408f166..0db32a661 100644 --- a/tests/api_resources/test_entities.py +++ b/tests/api_resources/test_entities.py @@ -819,7 +819,7 @@ def test_method_upload_parquet(self, client: Structify) -> None: entity = client.entities.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) assert entity is None @@ -828,7 +828,7 @@ def test_method_upload_parquet_with_all_params(self, client: Structify) -> None: entity = client.entities.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", start_embedding=True, ) assert entity is None @@ -838,7 +838,7 @@ def test_raw_response_upload_parquet(self, client: Structify) -> None: response = client.entities.with_raw_response.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) assert response.is_closed is True @@ -851,7 +851,7 @@ def test_streaming_response_upload_parquet(self, client: Structify) -> None: with client.entities.with_streaming_response.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1773,7 +1773,7 @@ async def test_method_upload_parquet(self, async_client: AsyncStructify) -> None entity = await async_client.entities.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) assert entity is None @@ -1782,7 +1782,7 @@ async def test_method_upload_parquet_with_all_params(self, async_client: AsyncSt entity = await async_client.entities.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", start_embedding=True, ) assert entity is None @@ -1792,7 +1792,7 @@ async def test_raw_response_upload_parquet(self, async_client: AsyncStructify) - response = await async_client.entities.with_raw_response.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) assert response.is_closed is True @@ -1805,7 +1805,7 @@ async def test_streaming_response_upload_parquet(self, async_client: AsyncStruct async with async_client.entities.with_streaming_response.upload_parquet( dataset="dataset", table_name="table_name", - content=b"raw file contents", + content=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_jobs.py b/tests/api_resources/test_jobs.py index 5db5dbf6f..e3119fd98 100644 --- a/tests/api_resources/test_jobs.py +++ b/tests/api_resources/test_jobs.py @@ -10,12 +10,11 @@ from structify import Structify, AsyncStructify from tests.utils import assert_matches_type from structify.types import ( + JobGetResponse, JobListResponse, JobCancelResponse, JobStatusResponse, GetJobEventsResponse, - JobGetScrapersResponse, - JobGetSourceEntitiesResponse, ) from structify._utils import parse_datetime from structify.pagination import SyncJobsList, AsyncJobsList @@ -104,116 +103,78 @@ def test_path_params_cancel(self, client: Structify) -> None: ) @parametrize - def test_method_get_events(self, client: Structify) -> None: - job = client.jobs.get_events( + def test_method_get(self, client: Structify) -> None: + job = client.jobs.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(GetJobEventsResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) @parametrize - def test_raw_response_get_events(self, client: Structify) -> None: - response = client.jobs.with_raw_response.get_events( + def test_raw_response_get(self, client: Structify) -> None: + response = client.jobs.with_raw_response.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(GetJobEventsResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) @parametrize - def test_streaming_response_get_events(self, client: Structify) -> None: - with client.jobs.with_streaming_response.get_events( + def test_streaming_response_get(self, client: Structify) -> None: + with client.jobs.with_streaming_response.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(GetJobEventsResponse, job, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_events(self, client: Structify) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - client.jobs.with_raw_response.get_events( - "", - ) - - @parametrize - def test_method_get_scrapers(self, client: Structify) -> None: - job = client.jobs.get_scrapers( - "job_id", - ) - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) - - @parametrize - def test_raw_response_get_scrapers(self, client: Structify) -> None: - response = client.jobs.with_raw_response.get_scrapers( - "job_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - job = response.parse() - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) - - @parametrize - def test_streaming_response_get_scrapers(self, client: Structify) -> None: - with client.jobs.with_streaming_response.get_scrapers( - "job_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - job = response.parse() - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_scrapers(self, client: Structify) -> None: + def test_path_params_get(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - client.jobs.with_raw_response.get_scrapers( + client.jobs.with_raw_response.get( "", ) @parametrize - def test_method_get_source_entities(self, client: Structify) -> None: - job = client.jobs.get_source_entities( + def test_method_get_events(self, client: Structify) -> None: + job = client.jobs.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) @parametrize - def test_raw_response_get_source_entities(self, client: Structify) -> None: - response = client.jobs.with_raw_response.get_source_entities( + def test_raw_response_get_events(self, client: Structify) -> None: + response = client.jobs.with_raw_response.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) @parametrize - def test_streaming_response_get_source_entities(self, client: Structify) -> None: - with client.jobs.with_streaming_response.get_source_entities( + def test_streaming_response_get_events(self, client: Structify) -> None: + with client.jobs.with_streaming_response.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = response.parse() - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_source_entities(self, client: Structify) -> None: + def test_path_params_get_events(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - client.jobs.with_raw_response.get_source_entities( + client.jobs.with_raw_response.get_events( "", ) @@ -360,116 +321,78 @@ async def test_path_params_cancel(self, async_client: AsyncStructify) -> None: ) @parametrize - async def test_method_get_events(self, async_client: AsyncStructify) -> None: - job = await async_client.jobs.get_events( + async def test_method_get(self, async_client: AsyncStructify) -> None: + job = await async_client.jobs.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(GetJobEventsResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) @parametrize - async def test_raw_response_get_events(self, async_client: AsyncStructify) -> None: - response = await async_client.jobs.with_raw_response.get_events( + async def test_raw_response_get(self, async_client: AsyncStructify) -> None: + response = await async_client.jobs.with_raw_response.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(GetJobEventsResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) @parametrize - async def test_streaming_response_get_events(self, async_client: AsyncStructify) -> None: - async with async_client.jobs.with_streaming_response.get_events( + async def test_streaming_response_get(self, async_client: AsyncStructify) -> None: + async with async_client.jobs.with_streaming_response.get( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(GetJobEventsResponse, job, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_events(self, async_client: AsyncStructify) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - await async_client.jobs.with_raw_response.get_events( - "", - ) - - @parametrize - async def test_method_get_scrapers(self, async_client: AsyncStructify) -> None: - job = await async_client.jobs.get_scrapers( - "job_id", - ) - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) - - @parametrize - async def test_raw_response_get_scrapers(self, async_client: AsyncStructify) -> None: - response = await async_client.jobs.with_raw_response.get_scrapers( - "job_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - job = await response.parse() - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) - - @parametrize - async def test_streaming_response_get_scrapers(self, async_client: AsyncStructify) -> None: - async with async_client.jobs.with_streaming_response.get_scrapers( - "job_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - job = await response.parse() - assert_matches_type(JobGetScrapersResponse, job, path=["response"]) + assert_matches_type(JobGetResponse, job, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_scrapers(self, async_client: AsyncStructify) -> None: + async def test_path_params_get(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - await async_client.jobs.with_raw_response.get_scrapers( + await async_client.jobs.with_raw_response.get( "", ) @parametrize - async def test_method_get_source_entities(self, async_client: AsyncStructify) -> None: - job = await async_client.jobs.get_source_entities( + async def test_method_get_events(self, async_client: AsyncStructify) -> None: + job = await async_client.jobs.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) @parametrize - async def test_raw_response_get_source_entities(self, async_client: AsyncStructify) -> None: - response = await async_client.jobs.with_raw_response.get_source_entities( + async def test_raw_response_get_events(self, async_client: AsyncStructify) -> None: + response = await async_client.jobs.with_raw_response.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) @parametrize - async def test_streaming_response_get_source_entities(self, async_client: AsyncStructify) -> None: - async with async_client.jobs.with_streaming_response.get_source_entities( + async def test_streaming_response_get_events(self, async_client: AsyncStructify) -> None: + async with async_client.jobs.with_streaming_response.get_events( "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" job = await response.parse() - assert_matches_type(JobGetSourceEntitiesResponse, job, path=["response"]) + assert_matches_type(GetJobEventsResponse, job, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_source_entities(self, async_client: AsyncStructify) -> None: + async def test_path_params_get_events(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - await async_client.jobs.with_raw_response.get_source_entities( + await async_client.jobs.with_raw_response.get_events( "", ) diff --git a/tests/api_resources/test_sandbox.py b/tests/api_resources/test_sandbox.py index a278863de..a485ed22b 100644 --- a/tests/api_resources/test_sandbox.py +++ b/tests/api_resources/test_sandbox.py @@ -9,7 +9,11 @@ from structify import Structify, AsyncStructify from tests.utils import assert_matches_type -from structify.types import Sandbox, SandboxListResponse +from structify.types import ( + Sandbox, + SandboxListResponse, + SandboxGetMetricsResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -101,6 +105,44 @@ def test_path_params_get(self, client: Structify) -> None: chat_id="", ) + @parametrize + def test_method_get_metrics(self, client: Structify) -> None: + sandbox = client.sandbox.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + @parametrize + def test_raw_response_get_metrics(self, client: Structify) -> None: + response = client.sandbox.with_raw_response.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sandbox = response.parse() + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + @parametrize + def test_streaming_response_get_metrics(self, client: Structify) -> None: + with client.sandbox.with_streaming_response.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sandbox = response.parse() + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_metrics(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sandbox_id` but received ''"): + client.sandbox.with_raw_response.get_metrics( + "", + ) + @parametrize def test_method_update_status(self, client: Structify) -> None: sandbox = client.sandbox.update_status( @@ -233,6 +275,44 @@ async def test_path_params_get(self, async_client: AsyncStructify) -> None: chat_id="", ) + @parametrize + async def test_method_get_metrics(self, async_client: AsyncStructify) -> None: + sandbox = await async_client.sandbox.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + @parametrize + async def test_raw_response_get_metrics(self, async_client: AsyncStructify) -> None: + response = await async_client.sandbox.with_raw_response.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sandbox = await response.parse() + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + @parametrize + async def test_streaming_response_get_metrics(self, async_client: AsyncStructify) -> None: + async with async_client.sandbox.with_streaming_response.get_metrics( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sandbox = await response.parse() + assert_matches_type(SandboxGetMetricsResponse, sandbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_metrics(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `sandbox_id` but received ''"): + await async_client.sandbox.with_raw_response.get_metrics( + "", + ) + @parametrize async def test_method_update_status(self, async_client: AsyncStructify) -> None: sandbox = await async_client.sandbox.update_status( diff --git a/tests/api_resources/test_sessions.py b/tests/api_resources/test_sessions.py index 97cdd8f69..f960c82df 100644 --- a/tests/api_resources/test_sessions.py +++ b/tests/api_resources/test_sessions.py @@ -18,6 +18,7 @@ FinalizeDagResponse, GetNodeLogsResponse, WorkflowSessionNode, + TriggerReviewResponse, SessionKillJobsResponse, SessionGetEventsResponse, SessionEditNodeOutputResponse, @@ -82,7 +83,6 @@ def test_path_params_confirm_node(self, client: Structify) -> None: def test_method_create_session(self, client: Structify) -> None: session = client.sessions.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) assert_matches_type(WorkflowSession, session, path=["response"]) @@ -90,7 +90,7 @@ def test_method_create_session(self, client: Structify) -> None: def test_method_create_session_with_all_params(self, client: Structify) -> None: session = client.sessions.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", + parent_chat_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", workflow_schedule_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(WorkflowSession, session, path=["response"]) @@ -99,7 +99,6 @@ def test_method_create_session_with_all_params(self, client: Structify) -> None: def test_raw_response_create_session(self, client: Structify) -> None: response = client.sessions.with_raw_response.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) assert response.is_closed is True @@ -111,7 +110,6 @@ def test_raw_response_create_session(self, client: Structify) -> None: def test_streaming_response_create_session(self, client: Structify) -> None: with client.sessions.with_streaming_response.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -743,6 +741,44 @@ def test_path_params_request_confirmation(self, client: Structify) -> None: row_count=0, ) + @parametrize + def test_method_trigger_review(self, client: Structify) -> None: + session = client.sessions.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + @parametrize + def test_raw_response_trigger_review(self, client: Structify) -> None: + response = client.sessions.with_raw_response.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + @parametrize + def test_streaming_response_trigger_review(self, client: Structify) -> None: + with client.sessions.with_streaming_response.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_trigger_review(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.sessions.with_raw_response.trigger_review( + "", + ) + @parametrize def test_method_update_node(self, client: Structify) -> None: session = client.sessions.update_node( @@ -858,7 +894,7 @@ def test_path_params_update_node_progress(self, client: Structify) -> None: ) @parametrize - def test_method_upload_dashboard_layout(self, client: Structify) -> None: + def test_method_upload_dashboard_layout_overload_1(self, client: Structify) -> None: session = client.sessions.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -878,7 +914,7 @@ def test_method_upload_dashboard_layout(self, client: Structify) -> None: assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - def test_method_upload_dashboard_layout_with_all_params(self, client: Structify) -> None: + def test_method_upload_dashboard_layout_with_all_params_overload_1(self, client: Structify) -> None: session = client.sessions.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -919,7 +955,7 @@ def test_method_upload_dashboard_layout_with_all_params(self, client: Structify) assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - def test_raw_response_upload_dashboard_layout(self, client: Structify) -> None: + def test_raw_response_upload_dashboard_layout_overload_1(self, client: Structify) -> None: response = client.sessions.with_raw_response.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -943,7 +979,7 @@ def test_raw_response_upload_dashboard_layout(self, client: Structify) -> None: assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - def test_streaming_response_upload_dashboard_layout(self, client: Structify) -> None: + def test_streaming_response_upload_dashboard_layout_overload_1(self, client: Structify) -> None: with client.sessions.with_streaming_response.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -969,7 +1005,7 @@ def test_streaming_response_upload_dashboard_layout(self, client: Structify) -> assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_upload_dashboard_layout(self, client: Structify) -> None: + def test_path_params_upload_dashboard_layout_overload_1(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): client.sessions.with_raw_response.upload_dashboard_layout( session_id="", @@ -988,11 +1024,177 @@ def test_path_params_upload_dashboard_layout(self, client: Structify) -> None: }, ) + @parametrize + def test_method_upload_dashboard_layout_overload_2(self, client: Structify) -> None: + session = client.sessions.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + assert_matches_type(WorkflowSession, session, path=["response"]) + + @parametrize + def test_raw_response_upload_dashboard_layout_overload_2(self, client: Structify) -> None: + response = client.sessions.with_raw_response.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert_matches_type(WorkflowSession, session, path=["response"]) + + @parametrize + def test_streaming_response_upload_dashboard_layout_overload_2(self, client: Structify) -> None: + with client.sessions.with_streaming_response.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert_matches_type(WorkflowSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_upload_dashboard_layout_overload_2(self, client: Structify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.sessions.with_raw_response.upload_dashboard_layout( + session_id="", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + @parametrize def test_method_upload_node_output_data(self, client: Structify) -> None: session = client.sessions.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) assert_matches_type(WorkflowSessionNode, session, path=["response"]) @@ -1000,7 +1202,13 @@ def test_method_upload_node_output_data(self, client: Structify) -> None: def test_method_upload_node_output_data_with_all_params(self, client: Structify) -> None: session = client.sessions.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", + cache_final_rows=0, + cache_final_size_bytes=0, + cache_max_bytes=0, + cache_original_rows=0, + cache_original_size_bytes=0, + cache_truncated=True, output_schema="output_schema", ) assert_matches_type(WorkflowSessionNode, session, path=["response"]) @@ -1009,7 +1217,7 @@ def test_method_upload_node_output_data_with_all_params(self, client: Structify) def test_raw_response_upload_node_output_data(self, client: Structify) -> None: response = client.sessions.with_raw_response.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) assert response.is_closed is True @@ -1021,7 +1229,7 @@ def test_raw_response_upload_node_output_data(self, client: Structify) -> None: def test_streaming_response_upload_node_output_data(self, client: Structify) -> None: with client.sessions.with_streaming_response.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1036,7 +1244,7 @@ def test_path_params_upload_node_output_data(self, client: Structify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `node_id` but received ''"): client.sessions.with_raw_response.upload_node_output_data( node_id="", - content=b"raw file contents", + content=b"Example data", ) @parametrize @@ -1133,7 +1341,6 @@ async def test_path_params_confirm_node(self, async_client: AsyncStructify) -> N async def test_method_create_session(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) assert_matches_type(WorkflowSession, session, path=["response"]) @@ -1141,7 +1348,7 @@ async def test_method_create_session(self, async_client: AsyncStructify) -> None async def test_method_create_session_with_all_params(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", + parent_chat_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", workflow_schedule_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(WorkflowSession, session, path=["response"]) @@ -1150,7 +1357,6 @@ async def test_method_create_session_with_all_params(self, async_client: AsyncSt async def test_raw_response_create_session(self, async_client: AsyncStructify) -> None: response = await async_client.sessions.with_raw_response.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) assert response.is_closed is True @@ -1162,7 +1368,6 @@ async def test_raw_response_create_session(self, async_client: AsyncStructify) - async def test_streaming_response_create_session(self, async_client: AsyncStructify) -> None: async with async_client.sessions.with_streaming_response.create_session( chat_session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - git_commit="git_commit", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1798,6 +2003,44 @@ async def test_path_params_request_confirmation(self, async_client: AsyncStructi row_count=0, ) + @parametrize + async def test_method_trigger_review(self, async_client: AsyncStructify) -> None: + session = await async_client.sessions.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + @parametrize + async def test_raw_response_trigger_review(self, async_client: AsyncStructify) -> None: + response = await async_client.sessions.with_raw_response.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + @parametrize + async def test_streaming_response_trigger_review(self, async_client: AsyncStructify) -> None: + async with async_client.sessions.with_streaming_response.trigger_review( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert_matches_type(TriggerReviewResponse, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_trigger_review(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.sessions.with_raw_response.trigger_review( + "", + ) + @parametrize async def test_method_update_node(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.update_node( @@ -1913,7 +2156,7 @@ async def test_path_params_update_node_progress(self, async_client: AsyncStructi ) @parametrize - async def test_method_upload_dashboard_layout(self, async_client: AsyncStructify) -> None: + async def test_method_upload_dashboard_layout_overload_1(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -1933,7 +2176,9 @@ async def test_method_upload_dashboard_layout(self, async_client: AsyncStructify assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - async def test_method_upload_dashboard_layout_with_all_params(self, async_client: AsyncStructify) -> None: + async def test_method_upload_dashboard_layout_with_all_params_overload_1( + self, async_client: AsyncStructify + ) -> None: session = await async_client.sessions.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -1974,7 +2219,7 @@ async def test_method_upload_dashboard_layout_with_all_params(self, async_client assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - async def test_raw_response_upload_dashboard_layout(self, async_client: AsyncStructify) -> None: + async def test_raw_response_upload_dashboard_layout_overload_1(self, async_client: AsyncStructify) -> None: response = await async_client.sessions.with_raw_response.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -1998,7 +2243,7 @@ async def test_raw_response_upload_dashboard_layout(self, async_client: AsyncStr assert_matches_type(WorkflowSession, session, path=["response"]) @parametrize - async def test_streaming_response_upload_dashboard_layout(self, async_client: AsyncStructify) -> None: + async def test_streaming_response_upload_dashboard_layout_overload_1(self, async_client: AsyncStructify) -> None: async with async_client.sessions.with_streaming_response.upload_dashboard_layout( session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", layout={ @@ -2024,7 +2269,7 @@ async def test_streaming_response_upload_dashboard_layout(self, async_client: As assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_upload_dashboard_layout(self, async_client: AsyncStructify) -> None: + async def test_path_params_upload_dashboard_layout_overload_1(self, async_client: AsyncStructify) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): await async_client.sessions.with_raw_response.upload_dashboard_layout( session_id="", @@ -2043,11 +2288,177 @@ async def test_path_params_upload_dashboard_layout(self, async_client: AsyncStru }, ) + @parametrize + async def test_method_upload_dashboard_layout_overload_2(self, async_client: AsyncStructify) -> None: + session = await async_client.sessions.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + assert_matches_type(WorkflowSession, session, path=["response"]) + + @parametrize + async def test_raw_response_upload_dashboard_layout_overload_2(self, async_client: AsyncStructify) -> None: + response = await async_client.sessions.with_raw_response.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert_matches_type(WorkflowSession, session, path=["response"]) + + @parametrize + async def test_streaming_response_upload_dashboard_layout_overload_2(self, async_client: AsyncStructify) -> None: + async with async_client.sessions.with_streaming_response.upload_dashboard_layout( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert_matches_type(WorkflowSession, session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_upload_dashboard_layout_overload_2(self, async_client: AsyncStructify) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.sessions.with_raw_response.upload_dashboard_layout( + session_id="", + dashboard_specs=[ + { + "file_name": "file_name", + "spec": { + "dataset": "dataset", + "description": "description", + "figures": [ + { + "id": "id", + "figure": { + "expression": "expression", + "kind": "js", + }, + } + ], + "params": { + "foo": { + "type": "string", + "value": "value", + } + }, + "queries": [ + { + "id": "id", + "sql": "sql", + } + ], + "title": "title", + "version": "version", + }, + } + ], + ) + @parametrize async def test_method_upload_node_output_data(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) assert_matches_type(WorkflowSessionNode, session, path=["response"]) @@ -2055,7 +2466,13 @@ async def test_method_upload_node_output_data(self, async_client: AsyncStructify async def test_method_upload_node_output_data_with_all_params(self, async_client: AsyncStructify) -> None: session = await async_client.sessions.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", + cache_final_rows=0, + cache_final_size_bytes=0, + cache_max_bytes=0, + cache_original_rows=0, + cache_original_size_bytes=0, + cache_truncated=True, output_schema="output_schema", ) assert_matches_type(WorkflowSessionNode, session, path=["response"]) @@ -2064,7 +2481,7 @@ async def test_method_upload_node_output_data_with_all_params(self, async_client async def test_raw_response_upload_node_output_data(self, async_client: AsyncStructify) -> None: response = await async_client.sessions.with_raw_response.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) assert response.is_closed is True @@ -2076,7 +2493,7 @@ async def test_raw_response_upload_node_output_data(self, async_client: AsyncStr async def test_streaming_response_upload_node_output_data(self, async_client: AsyncStructify) -> None: async with async_client.sessions.with_streaming_response.upload_node_output_data( node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - content=b"raw file contents", + content=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -2091,7 +2508,7 @@ async def test_path_params_upload_node_output_data(self, async_client: AsyncStru with pytest.raises(ValueError, match=r"Expected a non-empty value for `node_id` but received ''"): await async_client.sessions.with_raw_response.upload_node_output_data( node_id="", - content=b"raw file contents", + content=b"Example data", ) @parametrize diff --git a/tests/api_resources/test_structure.py b/tests/api_resources/test_structure.py index a87649bcc..1d33cc3e6 100644 --- a/tests/api_resources/test_structure.py +++ b/tests/api_resources/test_structure.py @@ -250,9 +250,9 @@ def test_method_pdf_with_all_params(self, client: Structify) -> None: dataset="dataset", path="path", instructions="instructions", - mode="Single", model="model", node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + pages=[0], ) assert_matches_type(StructurePdfResponse, structure, path=["response"]) @@ -586,9 +586,9 @@ async def test_method_pdf_with_all_params(self, async_client: AsyncStructify) -> dataset="dataset", path="path", instructions="instructions", - mode="Single", model="model", node_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + pages=[0], ) assert_matches_type(StructurePdfResponse, structure, path=["response"]) diff --git a/tests/api_resources/test_teams.py b/tests/api_resources/test_teams.py index af5d5dca3..38bc0ce81 100644 --- a/tests/api_resources/test_teams.py +++ b/tests/api_resources/test_teams.py @@ -83,9 +83,13 @@ def test_method_update(self, client: Structify) -> None: def test_method_update_with_all_params(self, client: Structify) -> None: team = client.teams.update( team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + daytona_credentials={ + "api_key": "api_key", + "api_url": "api_url", + }, description="description", name="name", - pipedream_project_id="pipedream_project_id", + sandbox_provider="modal", slack_bot_token="slack_bot_token", slack_team_icon="slack_team_icon", slack_team_id="slack_team_id", @@ -93,6 +97,10 @@ def test_method_update_with_all_params(self, client: Structify) -> None: teams_app_id="teams_app_id", teams_app_password="teams_app_password", teams_tenant_id="teams_tenant_id", + workflow_bucket={ + "bucket_url": "bucket_url", + "gcp_credentials_json": "gcp_credentials_json", + }, ) assert_matches_type(UpdateTeamResponse, team, path=["response"]) @@ -730,9 +738,13 @@ async def test_method_update(self, async_client: AsyncStructify) -> None: async def test_method_update_with_all_params(self, async_client: AsyncStructify) -> None: team = await async_client.teams.update( team_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + daytona_credentials={ + "api_key": "api_key", + "api_url": "api_url", + }, description="description", name="name", - pipedream_project_id="pipedream_project_id", + sandbox_provider="modal", slack_bot_token="slack_bot_token", slack_team_icon="slack_team_icon", slack_team_id="slack_team_id", @@ -740,6 +752,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncStructify) teams_app_id="teams_app_id", teams_app_password="teams_app_password", teams_tenant_id="teams_tenant_id", + workflow_bucket={ + "bucket_url": "bucket_url", + "gcp_credentials_json": "gcp_credentials_json", + }, ) assert_matches_type(UpdateTeamResponse, team, path=["response"]) diff --git a/tests/api_resources/test_user.py b/tests/api_resources/test_user.py index 17f025ce9..063cd0063 100644 --- a/tests/api_resources/test_user.py +++ b/tests/api_resources/test_user.py @@ -15,6 +15,8 @@ RefreshSessionResponse, SurveySubmissionResponse, UserTransactionsResponse, + GetOnboardingAnswersResponse, + SaveOnboardingAnswersResponse, ) from structify.types.admin import User @@ -45,10 +47,10 @@ def test_method_update_with_all_params(self, client: Structify) -> None: "feature_flags": ["functional_test"], "feature_overrides": {}, "full_name": "full_name", - "is_developer": True, "job_title": "job_title", "last_selected_team_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "linkedin_url": "linkedin_url", + "notify_for_interaction": True, "onboarding_session_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "permissions": ["labeler"], "slack_user_id": "slack_user_id", @@ -117,6 +119,31 @@ def test_streaming_response_enrich(self, client: Structify) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_get_onboarding_answers(self, client: Structify) -> None: + user = client.user.get_onboarding_answers() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + def test_raw_response_get_onboarding_answers(self, client: Structify) -> None: + response = client.user.with_raw_response.get_onboarding_answers() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_get_onboarding_answers(self, client: Structify) -> None: + with client.user.with_streaming_response.get_onboarding_answers() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_info(self, client: Structify) -> None: user = client.user.info() @@ -176,6 +203,52 @@ def test_streaming_response_refresh(self, client: Structify) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_save_onboarding_answers(self, client: Structify) -> None: + user = client.user.save_onboarding_answers( + answers={}, + ) + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + def test_method_save_onboarding_answers_with_all_params(self, client: Structify) -> None: + user = client.user.save_onboarding_answers( + answers={ + "company_name": "company_name", + "connected_connector_ids": ["string"], + "full_name": "full_name", + "primary_goal": "primary_goal", + "recommended_template_id": "recommended_template_id", + "role": "role", + "systems_to_connect": ["string"], + }, + ) + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + def test_raw_response_save_onboarding_answers(self, client: Structify) -> None: + response = client.user.with_raw_response.save_onboarding_answers( + answers={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = response.parse() + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + def test_streaming_response_save_onboarding_answers(self, client: Structify) -> None: + with client.user.with_streaming_response.save_onboarding_answers( + answers={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = response.parse() + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_survey_submit(self, client: Structify) -> None: user = client.user.survey_submit( @@ -291,10 +364,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncStructify) "feature_flags": ["functional_test"], "feature_overrides": {}, "full_name": "full_name", - "is_developer": True, "job_title": "job_title", "last_selected_team_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "linkedin_url": "linkedin_url", + "notify_for_interaction": True, "onboarding_session_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "permissions": ["labeler"], "slack_user_id": "slack_user_id", @@ -363,6 +436,31 @@ async def test_streaming_response_enrich(self, async_client: AsyncStructify) -> assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_get_onboarding_answers(self, async_client: AsyncStructify) -> None: + user = await async_client.user.get_onboarding_answers() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_get_onboarding_answers(self, async_client: AsyncStructify) -> None: + response = await async_client.user.with_raw_response.get_onboarding_answers() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_get_onboarding_answers(self, async_client: AsyncStructify) -> None: + async with async_client.user.with_streaming_response.get_onboarding_answers() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(GetOnboardingAnswersResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_info(self, async_client: AsyncStructify) -> None: user = await async_client.user.info() @@ -422,6 +520,52 @@ async def test_streaming_response_refresh(self, async_client: AsyncStructify) -> assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_save_onboarding_answers(self, async_client: AsyncStructify) -> None: + user = await async_client.user.save_onboarding_answers( + answers={}, + ) + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + async def test_method_save_onboarding_answers_with_all_params(self, async_client: AsyncStructify) -> None: + user = await async_client.user.save_onboarding_answers( + answers={ + "company_name": "company_name", + "connected_connector_ids": ["string"], + "full_name": "full_name", + "primary_goal": "primary_goal", + "recommended_template_id": "recommended_template_id", + "role": "role", + "systems_to_connect": ["string"], + }, + ) + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + async def test_raw_response_save_onboarding_answers(self, async_client: AsyncStructify) -> None: + response = await async_client.user.with_raw_response.save_onboarding_answers( + answers={}, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + user = await response.parse() + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + @parametrize + async def test_streaming_response_save_onboarding_answers(self, async_client: AsyncStructify) -> None: + async with async_client.user.with_streaming_response.save_onboarding_answers( + answers={}, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + user = await response.parse() + assert_matches_type(SaveOnboardingAnswersResponse, user, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_survey_submit(self, async_client: AsyncStructify) -> None: user = await async_client.user.survey_submit( diff --git a/tests/test_client.py b/tests/test_client.py index 7adaaa6c4..378c73e3e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -966,6 +966,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -1891,6 +1899,14 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient() diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py new file mode 100644 index 000000000..a181b7010 --- /dev/null +++ b/tests/test_utils/test_path.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import Any + +import pytest + +from structify._utils._path import path_template + + +@pytest.mark.parametrize( + "template, kwargs, expected", + [ + ("/v1/{id}", dict(id="abc"), "/v1/abc"), + ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"), + ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"), + ("/{w}/{w}", dict(w="echo"), "/echo/echo"), + ("/v1/static", {}, "/v1/static"), + ("", {}, ""), + ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"), + ("/v1/{v}", dict(v=None), "/v1/null"), + ("/v1/{v}", dict(v=True), "/v1/true"), + ("/v1/{v}", dict(v=False), "/v1/false"), + ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok + ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok + ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok + ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok + ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine + ( + "/v1/{a}?query={b}", + dict(a="../../other/endpoint", b="a&bad=true"), + "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue", + ), + ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"), + ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"), + ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"), + ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input + # Query: slash and ? are safe, # is not + ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"), + ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"), + ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"), + ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"), + # Fragment: slash and ? are safe + ("/docs#{v}", dict(v="a/b"), "/docs#a/b"), + ("/docs#{v}", dict(v="a?b"), "/docs#a?b"), + # Path: slash, ? and # are all encoded + ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"), + ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"), + ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"), + # same var encoded differently by component + ( + "/v1/{v}?q={v}#{v}", + dict(v="a/b?c#d"), + "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d", + ), + ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection + ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection + ], +) +def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None: + assert path_template(template, **kwargs) == expected + + +def test_missing_kwarg_raises_key_error() -> None: + with pytest.raises(KeyError, match="org_id"): + path_template("/v1/{org_id}") + + +@pytest.mark.parametrize( + "template, kwargs", + [ + ("{a}/path", dict(a=".")), + ("{a}/path", dict(a="..")), + ("/v1/{a}", dict(a=".")), + ("/v1/{a}", dict(a="..")), + ("/v1/{a}/path", dict(a=".")), + ("/v1/{a}/path", dict(a="..")), + ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".." + ("/v1/{a}.", dict(a=".")), # var + static → ".." + ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "." + ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text + ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/{v}?q=1", dict(v="..")), + ("/v1/{v}#frag", dict(v="..")), + ], +) +def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None: + with pytest.raises(ValueError, match="dot-segment"): + path_template(template, **kwargs)