diff --git a/.stats.yml b/.stats.yml index 96d65ef5..83b7ea96 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 199 +configured_endpoints: 183 diff --git a/README.md b/README.md index fd26910b..6863a3ed 100644 --- a/README.md +++ b/README.md @@ -140,14 +140,33 @@ from casedev import Casedev client = Casedev() -agent = client.agent.v1.agents.create( - instructions="instructions", - name="name", - sandbox={}, +response = client.connectors.v1.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", ) -print(agent.sandbox) +print(response.remote) ``` +## File uploads + +Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. + +```python +from pathlib import Path +from casedev import Casedev + +client = Casedev() + +client.translate.v1.translate_document( + file=Path("/path/to/file"), + target="es", +) +``` + +The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. + ## Handling errors When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `casedev.APIConnectionError` is raised. diff --git a/api.md b/api.md index c078f6b0..fa2a630a 100644 --- a/api.md +++ b/api.md @@ -1,68 +1,62 @@ -# Agent +# Connectors ## V1 -### Agents - Types: ```python -from casedev.types.agent.v1 import ( - AgentCreateResponse, - AgentRetrieveResponse, - AgentUpdateResponse, - AgentListResponse, - AgentDeleteResponse, -) +from casedev.types.connectors import V1SyncLinkResponse, V1TransferResponse ``` Methods: -- client.agent.v1.agents.create(\*\*params) -> AgentCreateResponse -- client.agent.v1.agents.retrieve(id) -> AgentRetrieveResponse -- client.agent.v1.agents.update(id, \*\*params) -> AgentUpdateResponse -- client.agent.v1.agents.list(\*\*params) -> AgentListResponse -- client.agent.v1.agents.delete(id) -> AgentDeleteResponse +- client.connectors.v1.sync_link(\*\*params) -> V1SyncLinkResponse +- client.connectors.v1.transfer(\*\*params) -> V1TransferResponse -### Run +### Installations -Types: +Methods: -```python -from casedev.types.agent.v1 import ( - RunCreateResponse, - RunListResponse, - RunCancelResponse, - RunEventsResponse, - RunExecResponse, - RunGetDetailsResponse, - RunGetStatusResponse, - RunWatchResponse, -) -``` +- client.connectors.v1.installations.list(\*\*params) -> None +- client.connectors.v1.installations.ensure(\*\*params) -> None + +#### Vaults Methods: -- client.agent.v1.run.create(\*\*params) -> RunCreateResponse -- client.agent.v1.run.list(\*\*params) -> RunListResponse -- client.agent.v1.run.cancel(id) -> RunCancelResponse -- client.agent.v1.run.events(id, \*\*params) -> str -- client.agent.v1.run.exec(id) -> RunExecResponse -- client.agent.v1.run.get_details(id) -> RunGetDetailsResponse -- client.agent.v1.run.get_status(id) -> RunGetStatusResponse -- client.agent.v1.run.watch(id, \*\*params) -> RunWatchResponse +- client.connectors.v1.installations.vaults.list(id) -> None +- client.connectors.v1.installations.vaults.grant(vault_id, \*, id, \*\*params) -> None +- client.connectors.v1.installations.vaults.revoke(vault_id, \*, id) -> None -### Execute +### Connections Types: ```python -from casedev.types.agent.v1 import ExecuteCreateResponse +from casedev.types.connectors.v1 import ( + ConnectionCreateResponse, + ConnectionListResponse, + ConnectionBrowseResponse, +) ``` Methods: -- client.agent.v1.execute.create(\*\*params) -> ExecuteCreateResponse +- client.connectors.v1.connections.create(\*\*params) -> ConnectionCreateResponse +- client.connectors.v1.connections.retrieve(id) -> None +- client.connectors.v1.connections.list(\*\*params) -> ConnectionListResponse +- client.connectors.v1.connections.delete(id, \*\*params) -> None +- client.connectors.v1.connections.browse(id, \*\*params) -> ConnectionBrowseResponse + +### Links + +Methods: + +- client.connectors.v1.links.retrieve(id) -> None +- client.connectors.v1.links.update(id, \*\*params) -> None +- client.connectors.v1.links.list(\*\*params) -> None +- client.connectors.v1.links.delete(id, \*\*params) -> None +- client.connectors.v1.links.list_objects(id, \*\*params) -> None # System @@ -167,72 +161,6 @@ Methods: - client.compute.v1.secrets.retrieve_group(group, \*\*params) -> SecretRetrieveGroupResponse - client.compute.v1.secrets.update_group(group, \*\*params) -> SecretUpdateGroupResponse -# Database - -## V1 - -Types: - -```python -from casedev.types.database import V1GetUsageResponse -``` - -Methods: - -- client.database.v1.get_usage() -> V1GetUsageResponse - -### Projects - -Types: - -```python -from casedev.types.database.v1 import ( - ProjectCreateResponse, - ProjectRetrieveResponse, - ProjectListResponse, - ProjectDeleteResponse, - ProjectCreateBranchResponse, - ProjectGetConnectionResponse, - ProjectListBranchesResponse, -) -``` - -Methods: - -- client.database.v1.projects.create(\*\*params) -> ProjectCreateResponse -- client.database.v1.projects.retrieve(id) -> ProjectRetrieveResponse -- client.database.v1.projects.list() -> ProjectListResponse -- client.database.v1.projects.delete(id) -> ProjectDeleteResponse -- client.database.v1.projects.create_branch(id, \*\*params) -> ProjectCreateBranchResponse -- client.database.v1.projects.get_connection(id, \*\*params) -> ProjectGetConnectionResponse -- client.database.v1.projects.list_branches(id) -> ProjectListBranchesResponse - -# Format - -## V1 - -Methods: - -- client.format.v1.create_document(\*\*params) -> BinaryAPIResponse - -### Templates - -Types: - -```python -from casedev.types.format.v1 import ( - TemplateCreateResponse, - TemplateRetrieveResponse, - TemplateListResponse, -) -``` - -Methods: - -- client.format.v1.templates.create(\*\*params) -> TemplateCreateResponse -- client.format.v1.templates.retrieve(id) -> TemplateRetrieveResponse -- client.format.v1.templates.list(\*\*params) -> TemplateListResponse - # Legal ## V1 @@ -244,7 +172,6 @@ from casedev.types.legal import ( DocketDetail, DocketSearchResult, V1DocketResponse, - V1DraftResponse, V1FindResponse, V1GetCitationsResponse, V1GetCitationsFromURLResponse, @@ -263,7 +190,6 @@ from casedev.types.legal import ( Methods: - client.legal.v1.docket(\*\*params) -> V1DocketResponse -- client.legal.v1.draft(\*\*params) -> V1DraftResponse - client.legal.v1.find(\*\*params) -> V1FindResponse - client.legal.v1.get_citations(\*\*params) -> V1GetCitationsResponse - client.legal.v1.get_citations_from_url(\*\*params) -> V1GetCitationsFromURLResponse @@ -277,6 +203,23 @@ Methods: - client.legal.v1.trademark_search(\*\*params) -> V1TrademarkSearchResponse - client.legal.v1.verify(\*\*params) -> V1VerifyResponse +# Linc + +## V1 + +### Sessions + +Methods: + +- client.linc.v1.sessions.create(\*\*params) -> None +- client.linc.v1.sessions.delete(id) -> None +- client.linc.v1.sessions.cancel(id, \*\*params) -> None +- client.linc.v1.sessions.ingest_events(id, \*\*params) -> None +- client.linc.v1.sessions.retrieve_events(id, \*\*params) -> None +- client.linc.v1.sessions.retrieve_messages(id, \*\*params) -> None +- client.linc.v1.sessions.retrieve_state(id) -> None +- client.linc.v1.sessions.send_rpc(path_id, \*\*params) -> None + # Matters ## V1 @@ -361,7 +304,6 @@ Methods: - client.matters.v1.work_items.update(work_item_id, \*, id, \*\*params) -> None - client.matters.v1.work_items.list(id, \*\*params) -> None - client.matters.v1.work_items.decide(work_item_id, \*, id, \*\*params) -> None -- client.matters.v1.work_items.list_executions(work_item_id, \*, id) -> None # Llm @@ -445,6 +387,18 @@ Methods: - client.media.v1.transcripts.search.create() -> None +#### Retrieve + +Types: + +```python +from casedev.types.media.v1.transcripts import RetrieveCreateResponse +``` + +Methods: + +- client.media.v1.transcripts.retrieve.create(\*\*params) -> RetrieveCreateResponse + # Ocr ## V1 @@ -475,26 +429,6 @@ Methods: - client.privilege.v1.detect(\*\*params) -> V1DetectResponse -# Mail - -## V1 - -### Inboxes - -Methods: - -- client.mail.v1.inboxes.create(\*\*params) -> None -- client.mail.v1.inboxes.retrieve(inbox_id) -> None -- client.mail.v1.inboxes.list() -> None -- client.mail.v1.inboxes.delete(inbox_id) -> None -- client.mail.v1.inboxes.get_attachment(attachment_id, \*, inbox_id, message_id) -> None -- client.mail.v1.inboxes.get_message(message_id, \*, inbox_id) -> None -- client.mail.v1.inboxes.get_policy(inbox_id) -> None -- client.mail.v1.inboxes.list_messages(inbox_id) -> None -- client.mail.v1.inboxes.reply(message_id, \*, inbox_id) -> None -- client.mail.v1.inboxes.send(inbox_id) -> None -- client.mail.v1.inboxes.set_policy(inbox_id, \*\*params) -> None - # Skills Types: @@ -543,8 +477,6 @@ Types: from casedev.types.search import ( V1AnswerResponse, V1ContentsResponse, - V1ResearchResponse, - V1RetrieveResearchResponse, V1SearchResponse, V1SimilarResponse, ) @@ -554,20 +486,9 @@ Methods: - client.search.v1.answer(\*\*params) -> V1AnswerResponse - client.search.v1.contents(\*\*params) -> V1ContentsResponse -- client.search.v1.research(\*\*params) -> V1ResearchResponse -- client.search.v1.retrieve_research(id, \*\*params) -> V1RetrieveResearchResponse - client.search.v1.search(\*\*params) -> V1SearchResponse - client.search.v1.similar(\*\*params) -> V1SimilarResponse -# Superdoc - -## V1 - -Methods: - -- client.superdoc.v1.annotate(\*\*params) -> BinaryAPIResponse -- client.superdoc.v1.convert(\*\*params) -> BinaryAPIResponse - # Translate ## V1 @@ -583,6 +504,7 @@ Methods: - client.translate.v1.detect(\*\*params) -> V1DetectResponse - client.translate.v1.list_languages(\*\*params) -> V1ListLanguagesResponse - client.translate.v1.translate(\*\*params) -> V1TranslateResponse +- client.translate.v1.translate_document(\*\*params) -> BinaryAPIResponse # Usage @@ -644,24 +566,6 @@ Methods: - client.vault.events.subscriptions.delete(subscription_id, \*, id) -> None - client.vault.events.subscriptions.test(subscription_id, \*, id, \*\*params) -> None -## Graphrag - -Types: - -```python -from casedev.types.vault import ( - GraphragGetStatsResponse, - GraphragInitResponse, - GraphragProcessObjectResponse, -) -``` - -Methods: - -- client.vault.graphrag.get_stats(id) -> GraphragGetStatsResponse -- client.vault.graphrag.init(id) -> GraphragInitResponse -- client.vault.graphrag.process_object(object_id, \*, id) -> GraphragProcessObjectResponse - ## Groups Methods: @@ -676,13 +580,15 @@ Methods: Types: ```python -from casedev.types.vault import MultipartGetPartURLsResponse +from casedev.types.vault import MultipartGetPartURLsResponse, MultipartInitResponse ``` Methods: - client.vault.multipart.abort(id, \*\*params) -> None +- client.vault.multipart.complete(id, \*\*params) -> None - client.vault.multipart.get_part_urls(id, \*\*params) -> MultipartGetPartURLsResponse +- client.vault.multipart.init(id, \*\*params) -> MultipartInitResponse ## Objects @@ -694,12 +600,13 @@ from casedev.types.vault import ( ObjectUpdateResponse, ObjectListResponse, ObjectDeleteResponse, + ObjectAppendResponse, ObjectCreatePresignedURLResponse, ObjectGetChunksResponse, ObjectGetOcrWordsResponse, ObjectGetPagesResponse, - ObjectGetSummarizeJobResponse, ObjectGetTextResponse, + ObjectMergeResponse, ) ``` @@ -707,15 +614,16 @@ Methods: - client.vault.objects.retrieve(object_id, \*, id) -> ObjectRetrieveResponse - client.vault.objects.update(object_id, \*, id, \*\*params) -> ObjectUpdateResponse -- client.vault.objects.list(id) -> ObjectListResponse +- client.vault.objects.list(id, \*\*params) -> ObjectListResponse - client.vault.objects.delete(object_id, \*, id, \*\*params) -> ObjectDeleteResponse +- client.vault.objects.append(object_id, \*, id, \*\*params) -> ObjectAppendResponse - client.vault.objects.create_presigned_url(object_id, \*, id, \*\*params) -> ObjectCreatePresignedURLResponse - client.vault.objects.download(object_id, \*, id) -> BinaryAPIResponse - client.vault.objects.get_chunks(object_id, \*, id, \*\*params) -> ObjectGetChunksResponse - client.vault.objects.get_ocr_words(object_id, \*, id, \*\*params) -> ObjectGetOcrWordsResponse - client.vault.objects.get_pages(object_id, \*, id, \*\*params) -> ObjectGetPagesResponse -- client.vault.objects.get_summarize_job(job_id, \*, id, object_id) -> ObjectGetSummarizeJobResponse - client.vault.objects.get_text(object_id, \*, id) -> ObjectGetTextResponse +- client.vault.objects.merge(id, \*\*params) -> ObjectMergeResponse ## Memory diff --git a/scripts/lint b/scripts/lint index 6532679b..580a84ed 100755 --- a/scripts/lint +++ b/scripts/lint @@ -13,7 +13,7 @@ else fi echo "==> Running pyright" -uv run pyright +uv run pyright -p . echo "==> Running mypy" uv run mypy . diff --git a/scripts/mock b/scripts/mock index 8291c9ea..515631dc 100755 --- a/scripts/mock +++ b/scripts/mock @@ -11,7 +11,7 @@ elif [ -n "$STAINLESS_OPENAPI_SPEC_URL" ]; then URL="$STAINLESS_OPENAPI_SPEC_URL" else # Embedded OpenAPI spec (base64-encoded, gzipped) - EMBEDDED_SPEC="H4sIAAAAAAAAA+y963bbSLIm+iq5uPqcknqTFCVbddE+c2ZkSXap2xdtSa7avat81CkgSWYLBNBIQDKrlmfNQ8wTzpOcFRGZiQSQIEGKsqVq948ui8j7JW4Z8cXvvSQVMU9l76D3bLg7HPX6PRmPk97B771c5pHoHfSOuBLDUNyyw7PTXr8XChVkMs1lEvcOepdTwQ5PBzHP5a1gacTzcZLN2DjJWCQmPGK5CKZxEiWT+ZC9KGQUMjXjWS7Md56mkQw4NKfYncynLCkypgqZC5aMoe00uROZCKF7Nez1e7ciU9T57nCEIw6SOOdBDoOO+awy5osiTZMs7/V7YsZl1DvoKfrlfwRciRnPboZBMuv1e0UGH6d5nqqDnZ1A1+996vciGYhYCaf1syxJMylyns1ba+7kIpup3qdP/Z4SGYy5d/DL77XCPJVD21V9ac+yJCwC/OPTB2glKDKZz7GZa8EzkR0W+bR38MsH+JzzCfWgx/gTL6JcNRq9gFYEC5OgmIk4ZypPMj4RtPKwIHEuA6YEz4Ip43HIXmU8nZ4fvup96tu234hZglOvDRg2RuXQ7AxL4DE4PGV8IuJctfexu8cmIhaZDJiMQ/FRhCznEzaWIgqV2/G7o/NGrycf84wHOcvFx5yNs2TGzo5fqj6TMz4Rqo8dqIDHsQjttCuN/pTIQDSaPSxCmbA847H9FZuCbgZ5MlCpEMHUbef16zfN9T4MAqEUez76NxbxeFLAWs+SUESK5dMsKSZTxlkRy7GkE+42eIEr1GjyZ3GtF6+PixurO5HpiYZCpCwT9LkyOLhsjabwV1ue5UkSKSbjICpCGU9YIHO8mOxWZHKsb6nb6lkmb2UkJs3ls19YKHKBpxhPgxiEUgXJrcjmOOBI5nJCndwl2c04Su4qm3OUzNIib7Z/gXcqgrV9dfYemzo6e89kPM64yrMiyItMuA29TLIZzxvtHJuLMMbvOUybtnkGxEywTMShyODnrTfHO3+5ePeW5QkcsZ3jd0f/uV3ZryIV2XEStHcSJLGmXtVOeJEns8bq/iyup0ly0zxU+gMTcZgmEq4bj/lEQBeV8cxVLmbNrSmuI7h/+JXNRM5DnnM6PnZvTNOVzXgho0jGk0aL7xUca2jgmkq0DAjLtdTOBFBls/x3eoaquLZFK0M55jm/5mrhwThLVD7JxMV/vGahLq6JkIxVzuOcXWc8DqYwJXfZbmQU+SinpVeZ4KFmX4enTGF5PN1E6NzGDumXemNHmeC56Ot1orsrPoqgyEWdYMKlZBzJSJ8pHofXyUcm4luZJTHSMqrN1TwOWFa03KM3PM+BB9UHQr8b/k1zggZUygOhsOUkC6ZC5Rnd0jSTMwmFq9N0ufhZlvxDBJ5ZA+Vy+D1LqWDLaam0eSzSKJnPvItZbza0ZTu1nMy4jD1bVKg8mbEQP8PNHctJoRcB99pppLXxk/iW/cQ9635SbiC75Znk15FwRuvp4QPIObM0iXENDn63AsFFMBUzgT+5YsHvvXyeCi1s9Po9hcV6B7pQr6//oQnjQe/w7JT9VTTZOvx+I+ZM5ZwuKB7Lv6ubKxBdrv5OMg60znEQJ1mWZE7/yTVscq/fS7MkFVkuaayiW7GZUEg1yoIqz+jG6h88H4Ik9H341O9l4p+FzETYO/jFNv3hE/yv30t5PsU+d/D+7dzu7ugLffB7byJQvtRilrnXIJcVsxkIgge911LlhgQ0OK1UuWI8gquMV01fcdjnfIocYCpALuK5gCs34bH8DbceRF5YEPzjNOwd9CKpcktXMqHSJFa0WHujEfyn2TWI0nZkIC7DjTj4veccsZ1/KCj+u97K5TtTro0ux7OMw/GRuZip5fVl6N07ukaeD5VZ1b/3e3ERRXCLegd5VohP/R6KWd6WbkE2Pg27jN0ZV719qQ5xK53S10kSCR7jEUQKHx7mvrGOzZ0LeS4GuZyBqNIr0nC1Knhqp1y9SbKWUcTiY35UZKpy01qWrCEncKUYVyzA+iD1jEUOUuJUMGiXpXB5PunL89x39E7jWx7JkP2zAJki5RmfCc2GNnQIVc7zQh1V77uMczERGSwAfX+zgIi0Exg7s932mWni+MQm9Kw5obcJEQgtajyhCSHltifLUYEjkFTQoNE76OER7LkMYMwjJfrNeZix9XszGctZMesd7PZ7M/6R/r23P4KbMgYa0jvYH9UpU+8NlWRxMbsWWUl54QZlIi+ymG3p+mx/BDLgR7a3P6qoEnTnVh97C7XsnfGJjEl20dd5i3b79Jh05jQTtzIpFF7q7SE7x4EqM3RNzdi1GCeZYPlU6k9DFEw+DlKRzaRSKKoc/EK84QDk5N4H2J9ELeWeJBJTqy3ysmKcxeJOH9RQjGUsSXUEiYQzFSSpsHdyyMA4RWUDHgPditm1YIUC+0Ki51QRvbMiVk1+SwUP9cCWM9xD6pKWbHMX6aH5JShFGRmc/BzwoRmqiOHP8BKsEPdrKZRqU01pjcu3PY2yn4nnt7LbN3AD4wkzdEJb0NgWnJE+czd4+wkR+K8s+LFPSCtWQuUvknAOpUpWRaLl2jNxFTYkdTVC9aE+WT89bJjkpEojPmdQulTCJmQoWEY6q029w3/wiDk/A9evtLiYuDZsTWSbcyuxfMo1zzNM7VpM+a1MsgW0uaGGvn5D5mcmQ1A3x1JkbEsMJ0PGYzBIpzLYCSJehGKgkjgW+eD58NvtITsmgQWFmAUlN8QM6sM+B/uTDLR2DWNQqQjAJM2wN3Z6rGzXr7KkSB+291taCxA7ZFwfywT6NyPaEE9r2GSiKLmLtGJPZvu8IuwUSgzZmyIveBTNmfgYRIUCswNKShX2yP7P//rfTImcJbFg+iIk+VRkfRYnObtO8umwt0Ge2riJIp4vmAmMYeFk3BXuOpfOTL3FKGjMsFWr4FaQFn399PVGvthu0OEgLbx6Ro0NWL3h6Oy9Iuqrm+xQm97mmIwZlP9k6XOLiH6XyRwtYP2G1Wvndxl+6mj6eiXyFsn9XOSZFLcou4NwEomm+H49Z6fHTbl7IvJVhe5Q5FxGG2SdX4Xuxy50Pwoz3FKR3GjbT0io+yp2P4UJPW8jhcDwxkkRb9AC8eVMeTI0tjB4pKmoBcSmO1vCDs1F7GS34nkwXcb73iO9aGF/9BEeUhtsb8jexdEcHkFvZVgq6zwTLJjyeCLCJksk2tSdK1L3oR3cV67YjQFtRpH4yl4fmr2+Tcy1yRNGLYPcP/vKdR/VhL5y3cc8oc/NdR/KVLiOHbDCIMEwYq2CK/OtJU2X34YMn9ahNr5DRYJnTI6Z9kyGZ7Y5mi6CSNIT26r2Q9O1arMjTgoZ3sOM+KZuQixNNmqaFFEIJhs0q44LcMTEh7UHsg3+ZAyANQsY0RUWykwEeTT3Lfrw4WyGP1VNgd6xtQ7pj2E0bJvdH8WQ2Da/tY2LF16rIvjjZnBbnetEk8LXav8ouhn9YACRyMUyDecYS7VoOBfJOB9QO46aQ26yt8mNUEzmqv4031BsqIHVzX1Qa4O8NrnxyblfDTxPZ0JfRc3HPKFHYuDxvnpoJyDooou/0on2GeLhYJoEy/yWYiZS8L/OIOTNUkg5m4lQ8lwgN8L24J0kK+LSAwtYD7j1g6dWkrE0oQgL2gpNZxU8R4K/k1RMUpUxV7lQObvjc3Q8K+KSOAO7SwrtHV8Sr0iORTAPIjH8Nf41/vOfT2ojtt8P/vxn17fK+IbNyS/MRqWAj5gObAmQ4aqSVYQ0/wZn0EwjZHfgrWXmDo7vxGC27qYC+DCTOVNFEAgRqj4bw6NPHxm1nAnFkiLfHrLa+BULE7w0PE1R4o7Zq5NLVn/2YiBDyHiiyH+MPPaMGH8awqyIPiZgvTOuA6Fl12M7apAhdJcQZidgzFA+EyiHvITdtCFzffwZwwBoHH2Uoc/eXXiGCAK94B77oD5Eh+GPSdCdmZ4XMXn3b5KVZgUOaZkqcU5HG9YKjrYz16yIdw5kuEMnHS663oLljdZP7ukx24KjONBndVvfFfoqVfVkthw9DCQk7QZlQEG7Gjp7WtJI3xhFDP6jv8DKxPDLh24MYBVHrzRLZmn+1bnrqxDy5Jy76Og2/bn070vv/CVXN4wKNx267u1+VfOAonhlHg3SIksTZSLnuAJqDpGFeiByjLTCvPEM7+mq9VT8sGiDN9v3BcgJJGEAXW72TZ3CEFzP7zsZRcSqtUEonwoldGGFGwLGMB4HXmvhEotKGErt/Id34GMOMkiQwMHhsozvojH/cUw7fyQzzib9wTKhkiKDwNk/jC8YnNsVwh/R0NsS/GiNVl2iHg1yh2JjGeUUgX89p0b6WvuhyGcKaBlAeHcI4Ss60GVB3OQ5DbJ76KSe1eYk482HTbbKxp1E0n8WokDh38imFGxsrGugX5FuAHQygn+je0RX1pwVMW0xBBHKTOVsbzQCLwdA7gBLwCK2uIkwC63ddK7i69Wsx/qNfI3X/KpPfNUnWm2AhoRtLOrxJXIOyzbQKFjGWGqquG5v9yWebUPNyBhDJo/HF8uK/PtxRbIa6+iiOFYcti+KFWytm45hBZmpPYIVhitjRqcGt1oM2RFAQ9SMfcYABkY91HeAiWk7sVfAcQJVz3EI3Ux/Zllqg3pwd8GNiCwfNqRuriNXrGWi07Pus6+2ukcxoT8Ub/0jPhh+DuNjKXq0mSE7vz2cHleCP/XjW28VdWmRJXMjxirTSMM81VEJa4TAGh+VctpGLiATZr2fR2kgvBYM39/AtOqxFcIbH1B0hwED0+BRdM2Dm/eZd90s2ygyuXQZf7y8PLtgpkX2/vw1SVqBQMQouMAWhrHllQokngm8KALL4Xky00+vBCXnPEwKkChjFEnwZx4IMFzSEYETDPVgujt3EATB+BjkU5RFhsw5SvhVZAqtjCqHxYR1DCGi4VZyLdMYUQZLd/ZPqhuiMCJxh8ToXsdn+iMs7RfJ8JMWyUBwBxOhloDwCf40FLM0QUBTWDItv+ODOYMoDjWlkloYJk+noMgyQlYF0ucR0rCV1YU0ozywLYCGi0AundtRbFCKaBHWlgtkpXrj1X8WvnY24UOFwqfZMUEactWYckfxC3WDJ8TwvspYT2FCHhkLLukTlbAe2iWLfDxWdsiyFN9EdXePRYdrX8aC10wt4CvLi1DmAO8sSTgxarmBPk6KPC3woUGkim0hCCtwRNVHBOhtenrIkxsBb2t8ItrD18+L+NgOpRux10Mnrj2G8cI4YLjBE1HLN/SSsJLAu9IjgkHJ9Yv0S54oiwwFRdOG4TI0AB5pR+6uTaeZwNeRtvdQ8x2dDII5ewN92DfH0+MhO8vEWGTs79rPIPs7ns6/Z0UMhorT8O9DrX/g1y6jMtsZ8nmexJxg90Hs+uC53NCJ8XHIGrK+HcXqC32m2xxYSV435vhEOF1coNlqhdmVZ1TlSZriwQSUZ3mL/wTob/wvQtU2Zn6kJT0zJrSa9Ukw57dcUpeowSo0sK76uvxSgoRNpIjMm6Uq2PBcx1LeG0Sf3q2hcn3q98YwhnNNtVafAuC3c+MwMhjzgGxisB5Mk2wHgQ9UD6lUIVSTDxr67pmgNtytOUPd4Qp1oFaUTLyPtd1CPMrpQjtowqYjhOjl7N9QIxEZo7pN7wFdfrkgfV5tWOVhUuQ7Kg9FhjcH0n/40ZJ9uQKCOcuWNEgD7zSwcoL1ZmiJi5rY0nGNL0umjFcS3HmD5oFqDyGXcVrk2Iq7w47MRRdqUQmQF8Ck3/LZeAu/afnePOytc695lSQqfyODLGkdV86j02Xzw1LvOkwy51F7gU/o7gToP5v3driRsZedGMIeRZD3APLafNAJWKRPgsARkrd6N/FC5NOkAx+zklKL3O51L1i8cyQhta52u8OCTOJVai3e1HuJXOibn/NZutBQVvHbMNkpoEbTmQKB50FA3/j5oh/az5fmtv0eAMDd0De481egI5h/a7b/4VNFYl++TEkSvW0JXvYWxvvsWSH6+s4KBk1IiUVkaBMbiDv0lN11vtqXnsSEvtqXHu90HoV9SXtx+M1L4naFJB8XeSb4DO+9rteQ8bGEgixBEVIWpzBGc7OLixPHvzUTiDlRID15zVU+OIGyAx8kosK2jVnp5LZzEpCLixNGlatHB4xZtAAD/dl3diqaz1d6+Ogn9JUePt7pfEZ66LgPcpUjtVjHvdJVXGvhQEi5NGmjF2K0/Clw2QD/AvIbXJ8yfxRBb8V4bN9L7wXIk8qxukBSjspTb+kPgJ6CMmYcY3orZt4ySLUam0qB2VkyyQDVxRuUu/J778bjcdd+13XDVRdbzbtbye8X9fqVxzyCCf2r8BiT1vFJMhuY1w/+eUnF4oRFSTwR1utlyzhZaOoDk38AF5M/Eo9d9027pLsrPGnbkIV6mNpkmt8J+H+DC4Jsyj5sD9l7JUquZZ6XjXPhuPYivvAt+8KMoTMfo+Jfmo2t9zD9OCxRK5rqGnAYEU8x6RW+nMZsBll6lQB3P/WV5T6dCf2rsNynyGkfBctZqEzdGTDzLtrUz+j069OljH8x462eyq6fsmp1VIZKs0JhOD+DJMUEsYM/IWgGgkgh2kaayVsIrIpFDtpEkz/h3FbSsY7M2DPrL/3QMIJLnMU7ReY64NZuY0/nnnwlzE9hQl8J85qE+XMEK7kXvxGntFo8ii/+pEbMSzcCS3HWiN/Y3wmmPO/KfXQc7ZkcQHfg+ZgEgLED0NVKYHdNJQiL3O4zNUtuRIlCiHjXgY2+1XCDR1yJYShuDbAMFEKAN7IUcnYmmYgnkGxPxsqENtEwDtM0EuwoiXMuwYdJzsD/16IvStxijI6J5lRlQABEccgmBirx8NXJ28urn/avzk6vXr87Onx9dfTu7eXh6duT86uTt4cvXp8c/7fdhSG+R1OeX9Bi/LR/JnH+nVjfmays5GfLVNumo6EXDiz1IvVNu/Is8mE1RWHoYhCY/cF6xkO03TMXHL9mrTSm3VksjMSlnImkyNu8uTYaV2wYZcrnUcKfEiH+F+X8ADUVDw7PTgcAbwqIRwhUSqTkTFqHSoOn9cQWwCMpEPb9E5UVWhm4fh3b0FRymUcrkRpfap4lpKctr9E9gRLW5P02neRKmPNLRIBWEPm1meORyxnLqIDPgy//L0ge/+C0EI/TEyWFD602Va7aym8pDlXZoWsddlUvKJwlpPC6GASwSP4mQofYEJkx/lIrKBpKxJDDz8A35AnqDaUyYSLNZbxAoTChXaAw3GU8VdDA+dkR+8vFu7evQcFI3GHjYMHBixwxmkqDXh5LGPWxWI0wvvV0SCvE9KJdz/U4H8bF7Kvk+6gm9JW0fyXtK5H2z5P2rX3uq4jWupV7BJZkSYt8X87TbkV+j37oa7sxBKgvWkDwH20noqtAn8qdIEviHYyuG2BsqPxNDEIuI9zUmi/De9yKCu99qeswrENher7gQIKlgV0PC0A9cYoz3S/h4Pwjuda2NzfxCBrhQp2c4ScMXWZHWRLrhCl49BQ7On/39uri5Oj85JJdC57Bq1YJSYyOgkWO1r9Q3IooSWeYj6/OX806HMMYcc7QVSeuetw2Ldc3YWM658rxV5hiRbnH0HnNCluirStNYbxkNlFm30MfUftUNXCXAy1HoLurN/ahA38NcN+LfJpkenVhUPte7Q+KKhFkIicHqdxmY9OIM81boGKeqmmSDyj/rM+nx3MPTmYS+CSk1jWxqrodZtrpcCv8DTyCKyFmMsdZX+hB6UTYnS/G4YKlgQk+hQsSJckNyMbofty9TTjhP8t8ei4CEdMq+iUBkvfhJOX+e9XvqRsJFgxqKpovKNvpDlZn5B9qfVytg/gSdxdOTZELzPcV38osiWctwT9HVNKDcV+p2HSPgIhngGuLIqZ7q9TA6zdPiqyGd3/iltHPHEyqJMIXo9J1XSeaoHaMOgkh/KQuamdrjxYI8Pcn1aF3iBuirQcPQcjNRXML60uwoftX35H1JCLf61MjQW4s/1lU9qWGKNIte/CPxYzHA/C6QU93tzmTQlhFxaTDeM5fDxQfLxpRmMy49KYhrjn7OS3oOghycWxgnhuUqt7CzzrFWu6kkzNwjs74Frtdtg+qzOe16sPYolaxLbgfJeFaI9l8w9bDlWU6TsNaYhYfOfCg5tH9hU4h/HrFr4PdvWc9c6R6x0lQ4IjPxa0Ud+6975nj0guTYJDh9165886vQ01ZhoF+x+5Vtlhra3pzeiQl9CoL3tsb7T0fjHYHu/uXu6ODZ6OD0ei/epUVs0X2Rpe7zw+e72MRiCqykwvF+Pn+t+XkwIYFOR3YYcyjuZKqnFKgPw14+cnOrPFxyQRNqFK3GX5/OfrhYHd/wQwrRT4tYkyHVWHIwjsPmGy6aBnLjle90jNsRxj3ciDtGuHhLAsgx2Nx56tRYSEE6BKB3QaYCJjY1JCd8GBaqTIROeFcJndxyZ5g+1UKGKJoU+WsIAJLG4z9TBNMq8gcBkEOf4dnpxqQlVKDiPqtRsT2IJmJVlJkPdkrLLXFeUIva/Xe1TihZ+MbxAZw0h3u+LDuEw/EwE7uxbHGmRRxCIk9o2LCQpEBbhYBVZnGunKt943zonOJVtjN4+NijteJIUEy1v/88BlYXI0NtXKdUHMdzT8GaZaEFXbj++oynsb3QcTvxjKbbZoFdXgB0JZENrCEFmYJhNfQYPxbL29X83ubnfedQ1Mce29bbJW7Yxp1GbQRGJCJrhIfISFWb6G7wQb9BfEINBwF1yMQECKWTnlczEQmgz6bztOpiHUmriIORaaCBOwI4PGGuGU8z0UGTf1/v/DBb4eD/xoNfrgafPi3P/Wck+s/ga2WScM6XanrgE6WtlS26Hk7v8MkPnVV9yDuqgunLZW+EnPcx2+v57iIZVqSCq/TyiodtBKK1OQ6o9tIK21wkUpl0mHfpmcZjzNOKSyLzA9Q2oUXei6ieypKpfBfnBs29Desei/NDXxxHyXfY1tE0PvMcLs+E3kw3H4aap3bQ9Sm4vkZ6+7es+f7JV8FOkUpYgeYAnYQJoGj9LR9tpwV414OdnaIo0KRzfDT0Q+LVTpiuUala2e5L7jLbhvcAFBeDadp47PvY2O/QzWpK9ut9FVy3dbHS/zPhp4vQRkhkYIyefhoOeXAQtLn91xp6HdNxzcv09Geb134zpnIZjxGoyqj1iEqyzNY4BlgkATFjSuVBBL1F5uvVD8XYC4McHrDwkYzDEUaJXMyTGLCTaA7rEhZJkj7q3Aurcv5tDSdvvVaMJNqXY4pH2vVQoryUZNfUaUNsCzT+8MwrPYnAYeiVN+ZvQ+4VjZyh/5NJHM5wYGBjAQdyXjyjZlSw4xfmu5NVx/Wv+1G2oYcx7SV+tC18Jc/Cjl4u5wU6Lvtbpt3pxaTioo8q5vsIs/uhKV40MmKdCFy76Y1gHMEBsN4SUpVtPBaYNg7iHuB5Ms1MkA0gGpC5A2Fpg8gVzMZidBkZUogWeJFnsx4rvPZFDGkdYYObca/JPbIuErkmoVugG649ALTSnNlxvgvKO9a688f9M3CwLuLhvT7NITc1reLVsGWXwdVybZVpm2RZmufNmYaGi0TZZ93sB6tJbz+QdhTg1iVbKq+nQsZlOsM5rCkqeBRPu1qVfkRS7NgKoIbD2mrJoWfOoUtk9HNMg3svci0QZ11e+um1uhc8GCKHoEbduv0bmc7PnldmjNGZ1PjQ/Uy2zuV3DiFDsz2lf6f7ubJWOWAeTOAvlfzhHh19p6Z6oyqt5nGFKoUNi2GpypZS9NMQo6IvjWkkVLR115KE8o6p9uRkcznQ3aKtjKh2OXzPjvcHeH/jfrsR/x/qPgj5Jt/dfYegJHuMDfe9Zy95rPrkLPX/FoN2ZnIxpAdEI7Y4alOWwhoSDGORsZjkSGkoX0co5bx5jBjvmTvjs5ZKe2BbKMCHnlOKHhjvEqLU70El3rxlp/S0+qiPbj5rTLAtZ0yugkklbnVZQm3ZOeG3J8hmVBaLK8MR5P2H7XdpCC5AU6mOBPZj0nRIb/FGZRmqYCHzyJjW2I4GbJv/rQ73Bt9g1YyON8dFu42SCtUowzuqzEBm6H79ujsvSI38FmSzV/J6w7Vzw/fQEzKK/mCRKQk4xPRreoFFbbViWjBRVWHNgvO8oPTxt1sG/r2KwMrj/uyfHiXkNDASWBeo1d1EitrF5K6qdHZ2qUo2fokLa52P17x3VFjHLsf2dufTo9PD4E4AS3q6eMIX+Cnrb3n7NULyvXinrTen0bDb6E9e2L0mXg2quzx3mhU3bnd56ORdy9+6RVqcCdUPtgFmUoNBMd/fwDer9d1d6+Dd57P1aHFO+8l4quBLAKUz7cLywxoLWxrfY61jFlB2fItRdfxu+8R7yoRv7WVXHvy0pN4hd1YlqX5HbE3HSMzg2EENaY0S2KZJxmu9anLhSzvcfjOP5JrzZ8grwgmjoMsFUvZ0Gos6PNxn81n+PAzpE5IgtdJktMvtfxhzj/R7zWH8xzzRhpU6XUwbsZ3O1TGO1S62d5Pi5lVGyfcDOAhppA514AbGmXQ65yMBY+MvaoRKLMGbEY7W2joveXJMt56QLzrfhNJkLnWO0dtLfcetrO3+/zZcPeH74f7z4fUQHX3qpzBbFyFDrdQ/RYe4ewTaML7HmXZuw+73wObcFYeOno2aqrfzRZd7vBZmEM3vtDRce41L+JgWmEAHpMJlLEucz4GoB3cjDGSXVz8CFNjExFruuqkdpjBasECWLghxMaANxg2lpFQcwVEDNiBbh1oC8KP/8+9wT6bybhArDyXEVwjNF9V0ej7dBYg/xj0oSCSwrIJ42LpuPk12QIuhMMYOrnI2VlQdQOy+pCYQiuT8S9GV/3ivsHkaDK4xRRwbRD1MoramqXWu8heM1hFgetriR3xbm5roDBt7lOnlXvW7ju1nJLQfbd3/SG9re6l6xrL++Jj6VNSUUtGzbLPvtEMZro7Gl2pj7N90jLbjrIP1TOJbWOWL1Era8HG+ECBTo8V7M2MdOpPHj+12jrYGdQ0MIc9Iz0c/CO5XofpljP7hf5tJIAPS1zPWiyhlnVZuJuufmYLGVOpmBB2NzydxyQDwbbx66SAV7SKUa30IAMeFSRxLNATxWSX7us7iZuhE3GqvqPEVFQHrU3oNxGirkNs2YCzAhekPnWMoRJBkQkNBuC10S5kMItsXwbB3Oofj5PRPGY5v5UfLdQAmujmdCK6iPu66DoCPwxLTX2btzgf6rStr0L5MAQJrX3GfclFabHhpP9V+NMQwz5m5O3lYeefDB19A/fNq7iukH/Q8GZ72ymxysb5eIVhL+G4E5FX2e1Do0ycupPfpAvWpVHcF1NlW0xRmgX0lnJr9AEyNSgiMgJhNm8gqv3SjQpsREaHMF5YnMi0VGA+Jv8uqmDdp4o4BG8HdhhFDN2AE4ITcpSUKIKCUeJzpLJ2ibXpb8Wy8fgI74YsEIsk7OYj+mrmg8oKesf77FuPpo4mATsu34ZULXELSYiua0Rrpw0nlOIREBY7sC9GXiqjWOuJXNt5V5EIjenBmIgdic8nIGJAgRHQTB2Qwyo27yHDlynFeCbYWOQAJQH2hlLsI7MBynGMs73R/8XSiOfQNRsLMWQvk8yVQiuvkehn6rzN9hHc/9XJJWt/cV70en+mV60TcuOC5Wq+ehNQwGqPBxpcYJIlRbok8r9SVCfi8fhmDNlFpaB+UxDWtVYPk23pi6X64C2ED6McRHh0utcY1+RWR1I3wE0jGaCnbtM1vAtAXjtYHwsp4H8VoIG9MnNdGyqgvmgb4ha6vY0+C7S42ZXv0NYBxZ1Ud38711Gn3sJKz9vH5V9t7d3XP+1nk7XDbZjdcWXhwjfgotbeiROVEfri7c32G9u9mjR4L/k08VQ2r6q5TLif5MGRCSV4FkyNT5FaP1y+Gs7YL0dYj5YH0e2aKzGAK90c5bH+7OruzuVvGyAG6+8tHOCeN9rdC/pYdX8knxwAHopDSB/nj8W29r17ONRd2K7Eiq51Ir6t5zhd4gho3h0aRHvITsfYp504MrRW99Jhp3yqpbxR9cIj1bGjJrMKWECFNixGCahcRMyCeh+uBdcLBAAZu/GJ4yImJbmGWEOLXXUnVu7Sw6rrkVkyZJBUfbvxa/xr/Oc/vxQc4h/VwZ///Gs8YO/MYM0gryFJwwT8ys18tBXUXM8+QhRA9zILB4DXN7dUYhuadA7UACqEGhhBJjF8/gkOPDfEmiaAgAnw8SiJx5EMwB0/13ccVg3N3MClLd/0QRk4PLrTA427bY8HxOBfkr8edQzmt4xtIfMoWcJyFuJeTnDQZjMe84kgAo8PkvcM069GEcnGg5OrL1r8lLEUUdj+FlWLGpL3c8tueXuyd3FQE0gWPUUZAlSJMmi+NS26iG74nEdh/QIgAAuj9r2X2CAuNC7LkL2BjG46HQviArBIQPOQGgPd8lQ7jsBw5bv7Dv8BPrmLL/E3iqVFliYKH99AaFg5XgZS22XCI8Bq65u+RJh9VXllJVkTL4bLMQ/09W2zM+jPO7/jUDq/QLn6LUrGyPv9EoNVdGHiWHgL2dk2LLOhLli/lBfLi9QuVLw0b0YyBwWSK/L7DvKCW4X6lkeFNl7AwmVo9kCSgAfLjsgFSVik3/5VzDtqt87aPLTXGy37A7HYFn722DgsnGtY7PU1/BvfM02HCWl+smkF+oFV585Kc2mvztKrisLMUzm4oftQD4cvBd9FqnOeJBGycNq4X/Qe9F6f/OfpxdXh2enVX0/+tkG9mlr/+eTi8vXhz1eHR0cnFxdXl+/+evK2rZNvl+rGe6OuunE7GlEp4oOos5aaXIOZI+fRJSBzbZq0y5qSbGV92jCBjceqVXim0cHpbGXJDHe4XaVfRc1ezMVXVfIXK+iGPZeKetEtHNthnH62C4VAn6aIzgqfNey0Kndd6CLALEUcZPMU1D0UZg9PLgZ7+98OXh29odzwKN2CZw7qApUzcsszCa/SFq2vvP/oB286X+BOqKxBX49pBZarGmHXnwOqATwnalx4DZZo6H3ZCAm8C6J3SiOMj12s0pI1IZjmLGdY4WXTrhDdc70mLraBNrDaqe45g9113yrtdvJbi8e8ImHVM+lbMgg+R8Qs+5rUPiZL5GehnG2YE7gvnyslrXlNayiYzjNbvX51en8V8wEK9yzlEmwEpSpB8cu9fo+HoSTl7syTA8MNml1PndtKtO6oGYAh/nUtbXt1LW1V9B9VY9qUH6guQxPiT8xAUsialRw0OrgoVvuqsgmUJHF0hLzh1iGbayZm5FPucp3SGAv8JQUhMLsFZbfaHplGcHhYuu88jxJHcay6uRLRGNvLxCyB1lpAgIiWrKK4kW5ZLk+FqRj0nM/DWNYlviUpPdYARrCr3xwfXh6+OLw4uTo7vLj4+d358TcUb0bz/Ka0E6KZ6ZvulrtVxNlNG+5cobXvdoR0PmmB5PzClNiRWOm+bkhivXBvsQUbMvfZ3h8ryOrsAfrFxL198HBioaI+t3xdDuv+4nUbOFJhbtaqTjaUaATo0bWMIr+LPLnYWN+XalXw7AKBK1BuKxU37ZbMDzYWFBx1oO7R2XuMGoc3J4xezgqwhIHroLaQXmeC34TJXYzPVxUrGkjzho8x3E3X9J4nEHiUiwzqWUo/Fzwjk1kS59NFDjkmxcdyuvu+46psjuimIpNJuLwczNYp5bgD4vQXfHrr90X89Mk5Vct6N75+izwSX6UFOHS7RbS4b30Wl5dIVH5Uy6Th83x8iRtR1S3ciV3PXcista1xwttI02VzybJ08ObsVGgji1Pn1+UBpCMGNiV7qJ5VzlDvDVjMerWDU67B8+8aR2F3b7jf2P1nw73mlJ5/tz/yT6L3p+ffDfdHvea+/lLbop6FBCJc5ooXqzPQZ/uezQHX1ZFnP77bq7i06uE+q/5aGe6zveFohKyqOjpfNglnVLt7nlH94B/U82d7nkHt7rev4e4+ruGiNBE1secnV+hxUKdaBRY8QAu9WP4GNLsk58SE0Bl8S3NVpPbGIRQa3O7E10sgDXu04SB/cuQFOtILh/cGirSMDzyQ+sw3Smx41WHOZCxnEJoP5gb+Uf97zxn/s09dnGpAlDDS8kJUK/OqXtPczFu79g2pQFc13/8R0ApkIF1MQ0ZoubLeWAkZblp33WxJjzKOBHW4CP3M6Xe0NR2th5NFY6f+bdOYUPiBUbNKNAY9BNiL6jB/9K2rwcRahLrVNLzq+VbwiFZNFtfwLr94x77/drTr7JseY+XcLIUAc0fSBgdm1sjFBDMnvdJAPfIfH1uGI+Pw8alxR9IsgX3z+VH7bwk+NJsWmK2+GInFcR47S1Q+gQQDjTas90EVQK5F1tZAORojhQR5jbvSZ2lUKBbJGLJaO6e3gYRsXM5L73rvU7NZibNytstvmSn84K/N7hY+nC+1no4OJ+n22mzq2GQyi1+Y66GA/sZqiGBdA6QPf77Q4eza68OeP1Sp4VyQaT2d/CQyVW2zDZtKH+aL/3jNZvwfECWvq3bCobHAmapQKab27BkzY9gkh0c2MoTWoYQy1VfhQv4mXsxz4dEp2toyl4iYu4zZNdanMEq4GZfeAKyWVgmpy1xGHYIcq2JGXp5KtwOJNfFqHpe3cf2zm7dE25tFDkrDQW20EHyfjB2agDGgHa5COe6VboNTzVyIIvOms26th+kkPjUsNq8XU7pCkSFXlkR3Ew4S5kI+DPqtab01vUOdsVoyWGOiJXk0sQbwSyPaADwpB6Un5SC89g1J+3iXxGOhE6ZFLOB3alDCtFVozO53Pijd5pXeHX337Lvnu9+DRuq7nBRt6LlYv9jlN1eBTjnwnKuP89+++/6H2ioA9g3KgHg8bYoL5xsBA2v0G8IV8oEPjS5H37di/9allCV5++6PStQUWrwvQKZYu6u+XzDSvvr1Xpb66y+XjFzM07eiIgWVOEYAU4owD46ncJokkYV+4NZY+w28Bn3DrjMOACvoT/BNLJI4vP7G9u2AIFE5E4xoUwaG4nZH5XyCoWgOpH0V7Kh+N9zsgQ70nQ0i0KCs9hmUKRoGM1BLLZ70NRGtkzf9cX2dv7xH/R9HynrMotRZQ4TSV+MFHvXNbCW1tdJO6iq0kQ0uf+y9vhpJ5aEZeh1lNTQ8w54Nd7v7pZpbXVl3kHVM1hpr/jj/zYkFLP0iAOR8Fe7s0BJLbkqCdC8u3Tg1OAfamCvYpatKxIfJi9AO1LdubIaTLrHfEprRdzEByiu6KVyAFZMsmqO2ODLD+97Wgd0HLaz4y0OIrRCX4ZJ1trUg4qKZtXHtkIt0Vepv6W/t6rh/75V/I2yX+VsUg0DAK0Bkq4iiRPZy/zZVeDpQCViH3H4qP+41qb2j+cOBsqfCUfzsVW5QAS/GmR/L7AvQqBYnJivCujEmPqtfG8iZX8KF5/al4m1HpDP7dN0QdkvYMyKkQpWRnKpvTBY7DZufI/dOLUaPtgE62vCQvUTQDLAP3nre/tH1BqRsIHkLLe6toma7MbCJe/ZV1vyXkzXLg/qjF7ioSwwonHBiDDOubly8PpkTA3h6RkFz3R/Wjn1fsXxzaa1ovovPnHcgm0tipRtsS0xeu28QFKn3iBxIAeHMiFZ9y3UeeAPtdVjJ9moqmU1M7mKR+d2BWutiHZYlkWnGo6OZNajDGpSb/Rhs345JGes+DcM3uoX/xDtu24knBKaMcnbj6R1nKa9d/Q9vS19Xt69xMg/T8fIMh9S7VMN3NdyVdddhie2gbtafzJYZ9Ot2Sud1fX37QJ3T90Q6+GchRT6YCR4mdwNMRv3t0DY65HdqCKbYYS7QWrLuO0DJS3/xWCUqJn+0SqyT369p47dYSbozbR6+Gu3ulf3pH6tdGiehbn3u1ZIaOJzHTDe8viKT9lUl3Tf91qvQf/3jFf6E7X2RV5QqdevZqAAkfZt6YemAK1/RCjZlHmqY2lfFpfXach4aQLIx6jac2uabUTNaqMXpTCdgXqZWNzOFwwtSQ3kutVf0BufZjWJSp47UGbtjm8yiCldbR6clcCdAwgiFyrNkjp486ADYVNGxsL2G5MSOtr2At0AU0njup0t/qSzgnjAueqrCKkzGIfSaZAuDhRrqF4T3GDOJqdUlHXjHkKP6UfnGZY1uAvKnSCLClmv0haiEk1F8Mb3oZKDbcTXjNZz0XGlrgZOevcuEdlpfyyF7YQqIGIVp9ylYREk6M0DXuaDAZfdZmMgBOdrBi7aM84GMdaKCKIHoxCE74cHUPGxJ88bdVKPoPTues6BQeTIrR24ecNEaQnJG34wGH0DGhCXnjnixy9+Lcu2WUya7QA9t3vvXNZWkHGxU1M2pdw5LbI5Y35yj02O2BeXpYaDS2fZjNczcXx3UjXf2rLKnrcZrFisZFTWsTcmobydsxlqqRxfht0U7qbzRLtJO6oP1THcNBWYlx6inxZXR7cqekkcusa/n5XVt/BoWOXlpaoPCOQYxWESKtEKOthwqVPHy2HaYr47CXcBKBUZL4MN55ZXRx6/7i/kk+GVVHboMb6ctYcGUxxN4lzPpM2ZyQqwUgELGIppje0TIQCRIp2ImMnxrFrdS3FV9x5Z4d1kvkuXOXS4F/aLPbPfnopvmeZvnzGyLR3ccQIWAUuI5Kc+9UI+Wly6wfNYW3V0x1wK60JupG6PpwFbWtpRtyquoHfL1QZlNktUo5HLPoheOV+s9sg9qFyIjeH5B1vVkHJYcqrW6v9JyGrdEjoc9A95HXLYSQgsXqZTquzv0rHBFN+KIs1O+F6zkk9N8y2pX9IF2O+4PTtX356etmr/1BVciguLA/40DT8UECB7nImS3ioUywwct24EaAlZ6daDKJqpxQLCxITVNiijEfCh5khEkPaZFIduifsJD2GVEPXLcyskWWb4dLhYwHIeecngd89XUZvPgan+5mO8zuZAbFplc5PXSODFsy5pbnJ3YLt0yVhJadCQngPyXS4oiNpyONSQObg6W217tIlcXx47b9lq747W1RPEfoi/+GR3s7EB2wYOUK3WXZOH/WO3Vboeek/67UhEkdP5veozliKw2bJYDWfrj0fAgRbWH23Z4pGkeq+pLO5AYaFOHvkefJw2Yl7GWWAj2nGwIPqnCBl02RBrdttu3PgEr9+2AkVU7B9rYuCps62zyIiniQGTb3bThOptqQ2Xq4Ce6Bi5TrW5HYCbgbAaGwpQhQBcnXsr4oWl0Jv28Tg6mkCo3VmORGYgmUhsw26fOGq9UEkjUJxHLiV1nyQ2A5SV34CVn+eUiJtMdgOl41WX4/EhMmGp2TbXsAuoayITqhpGrj1cK7NDwCWBZ+Jv9pDPu6kR+9cn5/SFNPrqMk0dLnSdTojuRHRW1JL5tfpaQljkVJfBuEcscTyQ8zoZJFPHMjes+E9mr6zc1ZKtlbb96gQic2pUTfkFolloP5sRjFyu3Xrk0tZbp9pyJbNWB62vXNuJxJso3meWeviWaLlR03RcpzzUdCUQJ6oBxejiZZGKC95+qMB5kiaLnMwcKw3tCjtoAvxZ7zNrD4R4JfR46N2bOgYzZqxeDGdV19r/L5lNLjT1/9cICbq2wL9RYbHenNBJbryY4Ecd645cKn9U1w8TnY4P4hN4PjVu1RvNmFRc2b9Zmjfbtsi7sgJZqjeYtQ1s0eoOXtfLKtzZKNLcVoqQuv8ACW3REh6ne72mzHIPPuFB+bXMtbaZNX3Kpu9zVJRfQ2euiArrnpmQHMaSL4kg+a76Z62F6v5nheT96HqFrcICeL3Aa4OHxfQMPfRGL/+SeorblWEZjLM4QynKF9q9pQwDUoo3OK/FsMNq9HOk3O8JT0iKKLfBs93Lv2cH+Dwf7Pwx/+OGH/+pVZY2mnDAa7o72vFx+NETgwRp3Hg1HPzQZ66jOE3dHFY5WP6jP94d7nrOpwQmd41giE5Ztf++nzr3nw293e37S2hsNn0HOay9d7I2Gez/0vDStB8vc81Gk3v5wb9SrUBXz/oybWvoAO1eevIOto2blutegEnXkXn3hno1ghRoL9z0uk7Nue8Pd2sXdd+6pvYm9Z8NdZ81oLdyFwl92f3C9pauLgm0QFmTlRtkTWXtDrl+g3QVoG7X0JSXgIZR/5ilPnm+hiCXiJVoVLinF3FLndAEUUdekKw+aptkEvIy1F1nCcKzqmvSbjZrUlzvNkrHArnjEIj5PCg9E2VES34osZ294hsymz/5y8e4tPlfm4iNlPMMIiaTSXjR3GN3Z8cs+O3539J9Y7cfLN6/LoThm01zMIAe3wLVI4nKgNjABiFiW6qSTZN40T6YQLiUVDoXy9ZSTjeQNhlMhlKbqs+tMirHG0MgE9t1URmn0x2ahu6iiFj2zDE/dupYxz3AtYBV2aBFwBeAn/bq73a6TpuHYq5I2+QD1hLYit4HbOBwmqYg/ziIqqgbJeCwDYcY4BOtdiXs6i4bu6VqtYzgRO9N8Fi2q2sGGJ+O0yJeE6it9BvWZsWdEZFmStadYXMP2d9k4lzU09s+Re8I00u8lRZ4W+dXY3vOG+Tv3wg83OD/4WCRFFgj3Eutm4fE7drpZED81A9McToYOAAVSmUDxWdjoWFMjbX2gvTaj/lSf34KO4W70e2ESfOz1e3DqrvR98oVyKTw51LYzScIQ76DV2uj/KpVSmKqDHmPyeUTZI/IcX20KyJGr09BbijARsbA5MJvyJ5E9jwbQNdhNj67L6+DpMVo/IFGNh/bqINxuZ+k0jmQs3FbsdtrESsvX+Cebg2nsXu0K1SdhfN6pvSNyfDUbY/baE8PWvOI11qMMMqj3AVNv7oG5kzV23Qqx6+PVPy7C0yXA5RL20wVRtfZdfb8Mpq7PzkpF1kPDzQQPpqjmPTj+7SL82qWQsW0wsclNBSHW0AIL/FrumzmBPpdy39ahQ7l2BSnrtj0zoz2sXtpuYhXQ9dJ+D8UYblomCoXszhIWLW6hIZfcEfQRJvdv+RsWv61csVahySFTmF/8pc2mAJtgXrLs63Z573kuJkkmRVPqSiPBIRqG+HaQZHToQhH7zig4RdISXzoLufyc4haAIbO5Cxs6q5VD8XBu5TqlaUkEK7DM3TzkLFXrCETRUtv9GYS8lnjqltpQbEefi3kbQ/DbuS7rwp0+teZA2xHhnezaGJTGdup4SagXd7WblDZz9JQrN2rKFbsWIkb2vwnPvJI3eQEI6sYZ53wahT+fpVEj5vft8aElK75npzjkWchiwOmRKogSBZ6ufJIJCv3Ny6o25JPueq+yxb/0MKPqLvkH5XOIcRVjcJSVt+CxCg38o8ikCiV5LHzoWxqLvivazULmc3IpxHFBKXe7nu91Sebed9ejnmn+TUJrm7BjqYC7t28EHJ6xRJliZmuFtpZeD0Pw6usRJEWG2R25Elf2GSGNuIQLPiaYJRGHPM7dxaCeoJ68lVF9AXa/b1mAkZMLtpOHfD2ZzlJNyuR7AK+oNoNIqwMDrtXCFAua9ZQc0jChLTGcDPuWxZQcpq8zr3fLsFCKGmWCQXuUvX4AdGfbfeJ9ooH2iK+xpRaPeO0QXytM4TdNdu9KBwYHtCSYBMXw999/Nz99+vR3puZxzj8SKjyPMZpV6YCwgJOU3GdKTmL0b1dmQaeCg9odACcbowSq+mycJOTDaCmzK4rEQvhSpdJRrTL4Tvy9Sgy/qMu6HcoqTusNlrwGN13GROtSSKvLj8hFkLvKn6Pt3J9vHbXg5dT9v73c6TWKoy/AUseO6Eg6nMb+UCWsXIm3hp4aKttKV5ezi3Vyt9ZsVC6cpNm6VUzJS3Jhfybbk3b217TaNNmwPD1GodSC/NgjY8kaQKlYsgbzKskaHnAga/Az0jQPMn79SnY3vNWsJKSmuRSapREPxDSJQmGe4ztaPC4uGJW1iqTlNRuiGh6hfAsAtgehISeymghxe4GIvnKnLcJ7m2VGs2rXsdyj3rcBPPoYObjtLePipYbvIDhWGXdJc6/n7PR4aIw2pZijFf1pcuc8ZbgO31kRwDEOkY2Xjy0Y1W16Ja2+AFg8xNtSBcSFK99rCDxHGBV9gc1oJW5dm9SjAHR8vIp1k4C03HJXETGCVlaY3PX2ZKB927kmXWzCFYRiCBiZgqUeMnDWacmDqrX3D9+2zWMA9ywJibSvK480tMMOurOzOxUZvqEzlhevehVmPJtI/TiRQNqqXfSIv05y4Ejmz0iMc/tHJidT8xc4AibU0pjPZATk6xKNFW/FHTtPZpz44W8wwd29FM31KuXkjNELk4KMvEqHplT5qIxzCwymg/3QMnCVjK/GnFz8eDYxz6dBAs6EiAP2wXMu4YfS8WCpbNYIB19JfKsG8jlyPJm33Vf85UkPTzvmei5pRodMzkv9+ptPeQXRtZKcmQe2Jrdqf5ldru4CC5VxKD56+OUFpXRp8EtYmosS6t7n1n7NlQw8GMgwAYPEhO2UqEqwVH0DSkuv+ZUkgxq4ScQhBn83NF337YQoJ7QPxq7kVmRzLw88TKWdyHL2R+Mtp/TQ7K8j85pqhEd9Pg7PTlE2bAADL6hvQghghp1ggZtNeBNC4lh8sYfl+Gwv/nDEwDksTq2D3u5wNBy54BMmXWD58oPSEkiGgcy5fReum3dQNa0e8jOegYhlamkMA3gL90RkghxGcpmngnZK0UkwSxnvRVSI6yS5cR8otwKD1drXfiwQlXGbRAX8kmLIBiREBRtZkeXbQwYOSGmumJAYOMYZqJNROXK04TE4lTSY6ygJbjyPMzD6I7tGncIA7VTFR5Q8Hy78z9279d5nkkxOZOzzzGyKS1SyXEGuiLgjtC2cAOKp8fJe62EijgNrNczDfvikXWwbTgO2h8WQBxcLz9eQvYWDIMfl5DQrgXjxJGeZCJJJDGxw2NwFsMV0IkdH5SEmg+6vvReFmrLbIXuVZOLXHhInPNQdnmV+woKsdA42F2P5QM51Scavr8GPBKdcDur98GJIg0mrjsBtQ8HQHXqOnbgjaknM3rTOBRLdALH8J2PRWr6eUKym1aQyPpJ5l0GfyRi2W7Atq0PC8LfpsMWw/xHs+PJxvLVly/NTqvckAHWPcbVN3LkXDOf6Gl+wReZADZe+GisAOTgGNiR+VjLrKgnKpiS473MDNb4URWxDPNmgNhdoo4hLVwuPqa8uXmpnTC4RYabOYfLEUF6PNLkRK6Hx/ao/l3/sZBKrjt437iE7Igmuyba2zCXdf7bL4KKyH77/tbftsLMyhxrY2mZFlMvUaQEtHjP+8bWIJ+Cp8+3z0WjUalWKSAJokRkGwMwHGru7g/BwQtOrSwOAaNsI2tNFwXOkvsEkOIxFBg4Vug1ezvv9+Wsnu3ZJ+O0a1jBLUbawrfdJTkMTjunCONBOighgPOfVxVwkMbzMktn7LHpkgkMntPULcph0lxXNmzKPumC8m2pU3oYSeUSWxfEazlkxkec+uadNRLpf/oFuT1ZmUvqxtlDnVkQdixDArcofRB4Mt91JdNRCmnwlWNl9IwlImQm0j5/WEO7l4LPmCgWPZw30tb6fHL3WMgTj7LEsA1kHwZWOR5Dl4D4vGCe6HUy25OoI05KaQK2p7PKERBGAk0KGkJC9t4a0ownXmnKNN7zlZZJdyzAUMdZRBYQZSIwNd9jnakKReSFT9usKItGxQ6QdOaLGaB9KHAJ20pCGWnjMQkQaGL02j9ScNNvntKLoAqJnV1sHObkSBdfvDfSWiW202ffwMzs9VmxLRcVEbWNVUPvoOa8wUOj6PtyAe6ngWTC1BjzCNILvZB9BfAlqFbRu+PB3/OHvpegONwynOaQ2t7ZbZBOY1ZGZQhdUI+gYkTsf2qhHXlGeQ9OItq240XWpIOP3SryLI7f5ZYpYJhRCtfBMgA9cjimX84TJeIDPjLiGiFjmU/MqQbnm0D2cEy1tExw4YK/CHBM6NgsOCUExTpOse6gz7HrnwivvVMoDCAotsmpkdsnSajXWUoA7+Pw9KGdYRs/1pUuSmyK1wRweF7+Hvnh1xoVU6nqujxWZ1jN96kAxZb+CMQRuTwyvh5CJMf+1B+pqPFch/SvgP/zaA4fFmYyNErpXUUl3R6MOJ6claMmtxoIkNHdXD/DlMRLhl5qqm0H22UsCu4si863PLvAneAUR270ORKSCZF0bXhzNNTE3hIMQhKwEoDkB6KYYwStn0i/SzWQsZ+Dqs4uLpv8NSX7sCPb26/2/oYJO9LseRZ7oYeET+nisxJJe3X5G7QJm2by6kSm7FuMkM+yMvMeQuK7IvmmROrJvfVwNA6e6ZD0gl+YmD69VoWNuKiaZ5YA1dxfYONzOxJxC7TMN6WylyX9ChDey7Hdrm1ZfJdGtodQoMRiv61zAUW9h48e0FJ2Ao2iE5O4MVu+HzJOyzD2NRB14zEfqhm9bHRl/Q9EIpgnG9dGu0fy29F+AtVfCibZalLv1QJtjCIm3B3ijfwlwZYfjFht8xZWjc9cIx089V7p5gTfqwfpZIM7o+4AfyRikTxjdnnN9s/t1acd71YyQ5S7qdkU0au2i7GE14JdFDzYNcYQmq31tu1ToeNJMyS743e62r77huvYlkNe4E8aKd7C8UN1WjFxO340vCtltHSBYRq7kqAmB/wq8W0V4mXTqw6uNWmmTq5Yo4qasCVIAQoWdEGlfQZ/QzIDdCeSEKP6JkG1pMa9GTiynq16AYwRF9Bz9xbf8pX4ZAD4Aj5lZtd/tr3fn69156LsDMkD9zpjRLj69WoDR1Xe09Fa9OTqdlHs3t7ur2ND0vHFSW5VOOhbrnafF/rO+S1TcMy1wy102La9wQXme82DqrbRorVacchqO3/uth57zvyiOtWkGUocWarhJuK0lIQWc97pJviOlPbN10SEOZXk8XWRD63Jmq7vXpgku0tfQvkCWQ99XBF2DLBHdmRcib4NHAmdQk50dHp2cs7HIIdmHl4MheXgp/LEcS9ZQNy4qPoVbaSYUPmxPRYyjOGBQu7lk2ob+UrgzbAMa5UoA4pM1vFO37P0FxrrN+MczskipfHljRs2mCQRTnmmwVc16y3b184tX6zGqEhQF9QhX+bggDfBNp6dTSP2Tc8AiRjwmZ7NkzGaAgqt0guAnaT9rgy6nVa4mBdnzJAW5TCALRDw3U1MIUSajuV4qlQoMGE2Z+BgIEQqNeL7nXyCAgL3jczZgRaryTPCZCQnKCKRpxbcgxxZkcItgTibBgfBiMS3Q+Z3teiiPGPjW9IhZ1RbQoiQ6FhgoyYqU/D1ghhhU1FtkRGhxwtPJZPI5/VU1IpTBjWDfxE8LTZb7aLLs6LdmbZWlzadq8rHG1JrVlP4xDn7tbS8yKY0lvFWBJWm4nmWiZbhRcgfIKPie6wADoOVg629/+9vfBm/eDI6Pt9e0U7T0WqRp917xTHSJ/tH3AxI+VvaaTqI293ZQ9KpZmOqxs5TLJPSLr/AWQ4zTmvCGvcWceVFvl5mcTNDVucGgdTg93iEgJHNiRfBAdH5ydHjG4HzLWwFuU7gWAGR9Eyd3kQgn4swwcmK3wwp3U3AZ84T96dlwNHJZnZoKkbM0KkBk+NNoONp3OeyQoUWceAK9hs5TccB+1aTg1x4uhW8UayzNudnhmuQAbuK2A0URYFb2UGzLP7Xt1llReuxrodcGXwsx7R4P0EVj+ACW/TPMBSB/Ew6psla1muxpkrTt7TuF+2x/VD/6934IeIcNLB3Squb/jI+7Wv+PoSxchoojQYMOvCL0J9EoSafScR9E9D41ZGdABUUIjIfHjE/QPQFOzpTHYYTJfs3ClmFx/dJt51ZkNkCPHAtvcVOKNEp4WHouckihCAQK4TMTTFzgSZsO03ytHwS6A3jS6kAH6IuPOUc29ACQFfFVlxfrc5rd//lf/xtnx3ZwKWGbsyLeOZDhjg6YIfjQBJLxoOiH5Tp1cWKTS9I2kaDQHrpj5BKduxKF79Z87QvF5jpswuogM60S8umqUvFPeLwW4ni2Bkvg8SLP/ocWISF/aVYE5q0bLwXsckOqrBRcegZ+hqsJAah44uG0kV9EBgqSuhmyE+1QXca9whOZiJjF0NCIv2EB7rAmaK5k2r/2qpLh7qguGqJwqME+l8nEFajPj5GC/6RpDv+ZhUsBR99p1E8ZmWhIB2e0W9AcSG1O0i5hkEQtii47BAwEDZtHIAjJTEJE/tBnc4n0OqxqBLgEFlp2y3Q7DR0Diy1XzXVztzwqLKDS3mg0gpS2hF6yj/EflOQMsmws2iWs1CP7k6ruivnUZkeBc4dDoQlBiNFMcKV5TDkcapoinzwOz91lH82AOXphkkRa86inB782ENrF20SuKklWdbxwAsKn6NCmpVNl+OxA3cgoUlo6KG/hEY/kOMliyQEtG9D3M4oXIe3n4vjt3+hf5o3eBJTr6Clkrq055RYt1E9QdY4eIKWLoYxhwEmSIuXIxABYpsvBDbQ2lxm75qFTtYhzGcF+g/5NnMvStKWXkGj26TFIrBm5Ao4x+s4RT0jUJLGBDBR0s65kuJr77uINpqFQ0+jWmCdMe5iRbWLHBkqU8B1oOktC0cGKW+/v9es3aEmMGNDZTIZiyI6dtGk8zqdZkspgJ4h4EYqBgsRm+eD58NsVxUnQkztKky9BpaZbQ5Nu9x0BSdotWIs0KQNMqmElZTiMtpvBObq1jrA64EuV8mHG4xuBqGahBGVYDdkhJV2+pZOMAixZCOiXrW3jhxPIvN2zBObaESkXZ/zQHiUdDTs2QNW15PRWdiT7S4WMkccHjp6uWJtfxAJPKLtBTgSL/W39V51OQTwNj2o6lCsE8lxCMdOG676vYpmmooO5CyPewI6apXmZ877SFA2qg9EGU/fqwZip4I3/XMEEnTEjH09kgb4PawUWXLhWUe05p22UPrfUDaoDdH0bwv9qrqrammtiJsfApcl3O50jfgzJEm9kBkA2DH9SDe/UZ3Xv1E25p4JyD/dB+wBWSI8ddGAlIhpsoQZa9oGBIvueGZ+rVeiSMcjsDvb2rWnogO2OtttMUWR80jLU7opBo8AUBiZEtgPHRfQxC8+QjJcZciwSGcpKtqIJq0nGDQsPmdA5GMU1y8SA6DJXhIeBluzXcD3qpur9OZWTaYRnicBWTpmeVwvHfSVycNC5JBiNTg6dJASa2T10ZEYnXnO8qUjRtLiOpJqK8LjFyaJmAYXigQ3t9XpdEC1e3tYhliPYdkLVbDTVLcz7ZSUU28BjlAdjJQG92vSPphEBDCoSt2CiABWDFEbnEi2d7amjxptaPgemKcd45Gy1VGu2miohQtYK39NPdU+H5d4rmA8mrLFx4FLz6KFZ7UPE7xlFvE62yaXiyJ6MDofJOFU4x8lGLVQY12g06rMZ/3jA0OZW5WPwsWRlWKDCzYir2wv6Hx2VDkPySdJwwhTtzXSYgeXpaJSUFKIF2Kcynvx3zc31NVyvf1A+TT6LeAJRCtRa2fMF/gDPRdA3gJlnRYTmk+0VtefWVC8eZn7/TC8lOIJJ9sJ+oiOmbGbzW5njFmD5OsaIF+TMtvq088MARiD5nSzvAPlapBdmkYkTk8c4ZK33wcTL3z8TTWl5rA69NjioVvonlUfPFaK7BvOe6zibity+wIbDq6L6NbmJlPLfjOfBFC5ZZTA2sldmaCszAb827hJsTlsUEpygQZjoo3kztCHAbcgi501VodOp/UtllBST/zjNNatbWPxbUTf9PHAA7l9qip22koK5Qnv/643tjr2LMmTlFBoQ3kjc+k2r5vJqDdGglfY0RgTMeVbEMpAp3Y8Fc6A+PpkWlqvcGBzvIoqxLTlm+ihdR+in6Quo+FymG33QcpHNHmfUb2X5K9figQQ/PE5rgtv/pX4uSxnjqGaxeH9hYmrpb3jCWRoAvJIsknJYjIH2J1wpPPT9xdnlO0YNMGcpWw38IF1QpXepiNkxOGmeJRkoPEDt31/4GkOCP8l4DAIOfXfzwULGZjSO4H5LTDYCWRUGNsrUupSg/Q1Tw+gwDrEj41sR50mmHSZ2YOP65CCX8XhiHhpKr/YhO4K3FVUdIjwah0xDY6JV5C88LkB63MWn0t0hTRYFn3EmQEMnr9kmr6IpXhj/zuX86YxrhelJPCkgllV3o1s987hlWL5jt9j9qvb4qsFpy61luu5CR7NlJkEbO4AUqz5LfzznIfy6dHKdWa5Tqz0+xXuEnJqgK0i78hSUkC+MeKk5h1UurNlA4Gr6KntYWme71yneWkJp14YvZ+iXLW4itUV35pojptT7XEICsT6DPLCTuM/OIh7nDu5YV+Bic7Qqy0kOWcY7mRZchAhbTaT9TMSh0Sb7PfJ0bbPiLfb/PcYcGFNRGQBCYmIon2fdcU/u2ZneaehHb7EfTYYI7n2seCZ9o2mLEIJ6ZXjevVKXmNYtj0juQA+2fcDJy+cXHc/CCZaub//FDHwl6Jt5RwmyxP7il/fWfXL74iZA5O6UrMkost1iQkhYgCFYNCcem7iQZTJhlS/W3+Ee6evbSyvOGN+jIEuUQt8afcOcxOY1Scd5s2O/ulN4I3IOAsjQJeIHu7t7z57vf/sdxkRYgerw7XGfvTvvs7fvLhmJJklG0KeOo16V5Ha9DWWG2NVo4+E1j8MkFqGPVHYg/TYsjEh8r98jGt/r95DIw38h6kihRbDX750LqVQhmnqefwbYn0N/VlqJJp2xS/EqSQDC9vXrIz1XQ/JW6aBCJqu8BTBWVyf5iFmN+XOdeBIUlxtRJWVX/ojpxR2dgKmnSzeWf91zQthOp47uMZ2lnWw4zKEppDbfANjePtr/4SlgM2EMJbB5omSuHRsdaZucV7L8xcI4TkcMcqWUitdopUz9EogIQ0mgJzv967np/F0WLrbkchXoRqt94i+NKSfozgmhi3ZdoUQfEnUCYx7LTOWrPhYY+2ZH3fxYiLRmGW2K+yKDk4q6YiamIlalu5w1p1YxsIm1YDY3VEfQA0AxHt6CTSlkIXRrzEQ6js6+4xh3Ps3LQjlGr8ecpdOMK4zoqnhaIe1tA28SIj0vJ7ZcPbZevI9EMz7LJL4r1RVjHoaSXqT+gwwZ95BhD21bxipCiabXQBlcycWP5tRNATM2IdC9MN3OFpyh7a+egg/kKfh5HCgewAHlq4vjY3VxtKS1VK4etWujl/Qu91d8QMrsslSUU2hk+j2gG6PcpqwUpzSC/Yd3sHw6npNKBAMSD1d72Tg5fnV4bqAu8VyT1YdNpYIsFm3M7OLkyNQ1Ppu2lVvJmRjnaqhEMJwkt6i/Y4w5R8Nc9k0l5YZWenSHWBsiGUzt8jU9lBmEl0DXOhYd/L70c7puZSZyjpAYMBW0MjPNWRQFdluK0CJ1XYjgJa1jJz+PkyM77Yf2r1wWFGglRdrBVUAzrbGvU9FcBjddwdrkTadyIKSDMLUiSBkw0jWhNHXtdREyFyivSzCX8FnI/8kgzq4txHE8dwueQ5yl9n9ECJDlSWZRAILAu/DdmPKWrLWEjUO3YibHbudttSOrZNC13LFLC7pUAe+Hd+PTOEiyNMla83m0rFObtuEB0QtXHNkGAOT85GnZWFqhAyn1TLtS0FxcEXgB4dZ7TygJ+yMQcv0JdPFIA2+FsWquXUG1WkE2hiYsLJX7CT0rsyTPoy6AUs6qafmOkDxgaBrG5tHDTBnu6YOi4I60U07QyDY6DZueb1WsWQg+tcjHpWFufGlHAKu9AJEqR7Acg0u1hMm2CMq4oWBAQ+OFNoOoAqar2O5o8Nc+/P9/9Nn38M8kY88XM+x2OtwyADBlAQYbVRyyn/BiwfSuE4BeKcPWK8eMQJLaZZqW3sqtg3mCtg/4PNMsKSZo7KtLvPrQtAs6tefy078aqEd3qDYPbcrDELxrMlbE+t+hnMi8hOjaDDqX+8xAmFk+ZK4NgXIt7+yB0hgYuXyz2QtIF9QeNA1L/2o6m5zJiJKfdo0u11WWRJljUYwjx5thmbutDhHybCJvRVxpCU3d4yLSEGpxqHNPOmHpmYjQ/z7NRCAgqSo9z5qGTdT6gqjxCz3rTuqVaVab1R/SJZn6aMGUbXP5ohhAHcv2hWPIlW+x0LRKHy70aflsJuLqgB6Zkfhf23z7FOPl9HFCJ6O1wtTtZf28QeqbjpxrgNBZNM8GAchWJ0utNlLsBamUTcvzBY2jfcoPf7bsFncUVU4v3pGEYtYSEKrxMTtz2Kd1Xt8b7Y0Go93BaHf1kLg846GY8exmNU/01xrTlhzFbCPMRlfVfPt08XpBEggwP4QqCSM1emnLkpcT+7+Zjbs+t3GmW5cXx+fbTM1VLmaON5XW767nVYdayog0gRRaRD3pZzdGKrvBuF+NeQMCBfgH9dkkSUK1o++66rO3cOWDCNyISmxEkvJ2Kl3gUyj5s8+SzGPptauygvN5uTp6pg/9yk7L2NUNmbaw4cvsrstqTXk2Db2a6XdAt/Q6NsMKXXZLcj4VFrcBEc/MArc22+m1HUqRi3l2U7qh5oDdkYXMBhUzwHMnJzvykNM/eCe1qj90zc/v3C5ZzavP4/F3BCw9iuDPBUO5hwczLE2CiToDZ6hF2ibVfF7/bPfU3bNPPADQWXlifT0isfHdRv/WYvEdPZ84d5MPeFDL1jRj8zBEINMHsQ3zPE+yWHSBftAliWVDQiCvSz2Q6cM41FLbcuvSK6hAuXJ1FeYU0O95SOc13VkhJASrrZCsZDVDOa5fLANxBN100qXcnGhVaajJzWqTBi/YGZ9000l1Umd78LEmBGoRNT86futN26PSPOnU/hGPk1gGPGLA/zFtt467l8TDV1FDZgXA3VL2A+byubq08NYyssfhye+3xFvJwJrfLSQBGVlKfrzvBwLWydChp2o6iI6BA7gnLdEDKylZjrxYdZeRauX0Eg2J6WFs/xuWmizX/uE7ihrAoIEzfViFxEDt5Wd2+ADSlx7Yt/cc10rqCoFadVRSNDxqHTm2PkU04qMLY60k4xMOyM01eEuwPbKI31nNdquK3GGAL4FP/c/d0RsyVjo4XBUwVkcRwoatywia5jn4zxoYdrrLOgsCYrujxFpa7PWy27cfWxPBIUqEsesoCW4Q8YdLTG1r3Y3t3JtaCi39kbOMHTKx26W04DoPpJ008KPa3oVb/B1a4KDs+K350gPX2xrq2py9OVGZgNbhXKDdIslfdjSwlm2W1F3G9swhWJHezDfgbyS6mELKRqvO52milARKPNNNtUI7r2i7TbTJegXjtj3LXDkXQYOUqZR78541gGqyFjcY4c8c+6kT9r49EriTV3RUyn24Mqv3wR4fHb3V0UKrTYXJuEo5yGzFtqYCbGO5DOihhEfRNQ9uzJ5tD52RVsFq+j1bFceG3DQEVGRnTG05yGxZphCZfmt3SDk5KsSwz8rRUTl3jNtDOv3ZjEcgNC1fire2bHkgSt8NuFAddKcKmd1CPzyzhUuyijonxq89wXmZJlnuTzjanm9JP3Iei0CGvnVYmpqUEmvyKBLR0Qr303kMb3N8WeLQX3vttIykDAygFa7fBuBJ5dlwD/YKOTBbN2H9ZW71/1nLcSfJGMo0gNIJnNfKnPdQIlaQnxuQYqu9UVwaOFItJtTlozzRKKQP5jwD9L3pPNPNoFcbvGfYQ3bEY0Ckb0pM1ri+/2yXvR9eDNkP3//a23YkqWrWHb8E5TjPfPt81BUiRsYBOVGb701p93CC7nEVcfcoE2BsiklKfS1jgGDBJpokEItCZoNjPs+TmA+AHIvQV1lnFQqSVIcGD0Nxy4IM39slj9SQXYLWbdCiKD0PAQUqHofXyUfGA4iDhVeMf2c6O412774lLNg04nMEn1ICrkguFqGKBTh6GOMFDfGn3U7SaGVW1AiKdHs+vbZSWCqyD8Afmk4szKGT8jmkONg0xt5RErrkzuFG9P1Na+KfTkmBOmT4eVoT8tDJt4lOrETOyXCfcaczyH0xw2Q5QBuf2tZ1yKH0dCbUZEslT9B5UDYVxOD3AOmeCQSMomEkIHltUuQtiW4bVTCpyum9Up7AOiNJPkzlX/3W88U5S0qfRhAas4G2f4YNSq+vvrUh6psyJFiExXmtluRMzuStjARkHTx6NsA37ikZQnmaMrdtdBFLMcOttiobznL46uTt5cVwFuJ4MEPPBaQRvcfSNtQvSvsD64AZSmEIMDiABpGxHo+hH2ZcOmsJfNI81fASYo8LDF9Inw7uMpmLFolg53cZfqIbD0++ywQDwD/wSwW1xHzY2j35qoh1Zp+v/OSPxU8qu/xE2Ypj8j/4xaiPoOIDKSMMwKlHl2lMwbb7Yf37uxPg23pn6R5LewV09CZuCMlY3rnMl0XW9ULrvjialb/e5q+3+RHO67HdZtRkceo1bHnfZT4nhde9zLp+08Gf3oxSkSmw41hOfiZ3ynpMxLciSlLQqhEGFUUSkqHBVFpkKsmG7DVUDAVkk87moNRS/l9MDAw16FBQ2JXBrPdh0DtU5QSH3ZGuvG3O91+ZtEQJODB8JTCPc16fl8Bkgocd6MuOBHBkb0IqH505xdJeoaGN3uiDSP2URj1Mi651G31Y1ZC9hPVRjGfCIVBjfOkHAvfviFyOz3djKilmMqfghyJDG3VTd2B34nqaJDdNykNj6kR82gx6NOuaZPPVkPfYJ7SIniJr1lT1iU3rK9l8eLnMPDesJpmV3vQu7bRttUlpZTUjnukqEGSLcHChyCSAsmCwgyGCTTlQv6nofEsqx2J6YgPTJvAMnXcYaC4Z8qAGz1ksBNrKNFkm7ytMAw9JqXKLbwOPOwmkShcpuYGDkyZnICKyi4sTLQ0ukwL1eekqBx4tXt1/PRr2VSZ8GvN6ZDJhlgZdJcELETuqIzs/OwJiNeO4/A1/5DuegU98Xdd0apns6lVz/MA5vteZDCfgkBBMAW03BJImWJYUgL+r6SUpq2dSC2SKyBQ0TIRPd/bvZiBGfMs08bNgCFP7zUisTZKlRBw6NOs8DTpKjm8ry2bKf5Udn8aEvpr5vlLczYmTNrNYB1kS8kH7VG+T32yRRIWpydZ5f6PGv17lr1f5sc3rywlP0WyHIoU8F/f16zeea/v69RsbXGSiKRsqH+JrkqByeMpe6SCoSjUm4yAqUK8Cd4HSNzPi8aQAJQ71N3KGoxycJquIwXuvOtcZyYnUPifck7CpcnTXNxk9Id8sPOQdnrKL47/aEVIdyDtwAwOTORNczcmtIRcTdL/DJsRH8M6NJ9CAmxNr+Gv8awyZ6PPK2PLk4Nd4wI6lIkWzdbZQClaZJlGdMOV9y2QAIckxuLDqEC8ziyCC4Dhs40UhI6MBKxGJQC95LrIxJyiiJo2NZtRkJ9Lauq+4PuUEaV6bu4y6veVOLPdI//k+lv8shDlJ6M05louc2xug5MWMxwO4aOUa2GQn+NeKMfLYgPa8NUemz8TsWoRwhbaX4jc23NGxRec3HWeV8mtISCM1djqdNt+qNhyWArwxzrUzblHkMIaxKM5xXt7mpQimFMnquQeIRVam4TRu0UgwcaHddf7QyHWsT1Etw7E5W7/QMelN0nzw3DR40Ht1dol/OhvYM5vhWWCV03pGgmFN1yCFZp6P2m2cxzyaK6l6lQXHMLbewWg4etbvJUVu/vq23wswxj2YYxTiMWZ2BmC23u5fWZ7cCEpPqucQRLwIxeDZIEkRfkTP5Qh/Zs/YO/q505wOY1ArUxl8owibIAWYOgAiK6dmcnZwZRyC9UDAN31gT+zg2SDiGfahR4Re6SfmO3vGXuvv7tBs/eaVk5Mp8Ds8fxB8Y4tSiLASMx7nNvlm79OHBXrdYZnDHE8yx2ya3uAFG37gdV6PZnV2e7u7A2bGHW0QbU163WC+R2CcdGv5XdcZdwrZO2h9GNMsmaW5TiFqRA5IIVplkZAN9fD0G0UmUadXzL5egsk8H/2b4dMlP8fT3md0xPrslQCkIIJ5Ad/JNxhpjMfk8FTXHrJTrC6UtqsiNCn10qdDzTDpsYwn1FKBht484wGw6jZXeFi0Izv6blh2NgzTXUhr29gYI1uBEZUsyG5oOTRES6QuPO1Z6taDnRxWqxlPf59rbmMgHxk+beZ8lmJ+k3JtsBndZKt3sI/9YJKVkh7aYU2TFnyKrjw+DsVHv6zelMRb2siSFv9nZ/sbsjygsMRSTa+I/vnlfUBz6DQEuqtXmqR7p1Mu3MJiGNu7pCHlTqk1tlEBkgoDrrMk6svo0ybyqwOE3ekC6tqi5BoX7DARFPc75bfmyRPEdtBWLCzEIu/5DYZm2deaRnjWSpdD55yvXo8hOyZwNZwdRHUCbsMOxI8SP2VyjOugRSZU7x0a0KzgXIrlQYwmE6mNVMJ8XZKi+JAqxZCK2uiFHa+r/6o5kM8IYQZijsIzCVAsKockiQ3wZzKkl6CU5kGQIgcXXl9fU7qwqjWnr/GMf2y/U21ot2XiaKoK+ziBIESyfNm90plecjFDtlZUEH5brucF1KWISluLXYv8ToiYjZBt7rl9jIbfofkCGK7T+nWSRII3FfufpwJRFCArDLnCYTh1Cmn1eASixSQjVwPbAwal6PhjOHhXaprcXZXS4fJOjcSAURAHlBsELyuYDZI7VYqaOg0p0CfL5av3BUcD6NumhlQoZMCoRUjx4PWR50l6lS5f+rdFEIlCMWW2oBLPOka6Ewfzq1TEPKpgXbc0+NJUYbpKtUUYM8SYd2/wTNfwtdcafBnBtQPJoSrBlrJ1R9mVRFOnWovweiswHtKV3RH7EHSDAskMSaYDx6ZjJEjIIQgPbx5pv1/GpJbopCRHXoOlBBo+P3ylwRKVo8hYUMk2CfPEndNy6bIsbuIsHwj3o4tICHgHOvKbe2h/V8iKDj2VehvGRrWKZ2W55cMxYE2aGPt560alrWViFI3EMSiYpaGVNgv9i/PBVWj1uowqy/DLaDga7T3rD+C/33/XHw1Hu/vffgD7rp5yXbPmIR+MRns9Z+a1ue3u1eeyu/dAstwDC3Atl8uOtG6pfhCBjyw1Zj8aUp825PzeS2LxbozbXz+jS8+6a9b3BPND7D3URLFCfNTSYZ3oGqDhjmJouZozVyDVVkj/oWv8/mygILP8NkHJBAn8eGWAIdtFvnGUcFhSQO759nktu67+1vDNmPFcu9hqbDWH3wCVkzPIK5t0EtdKDOSymlW+nSXdwrWxCc+3ieB0wg9r1e1FHA6wjVa+jBy5j+y5wpengkf5tNNbzo9YlAVTEdx4xsZLC5gI2dQpbIfpXE2/F9zrN9RJN7NLiV9X4nBs+AnPyx4MdfFctuo1twjOpkbNemz66CU3TqED3CWrK5udKp8xlu4UKl2tL0atz2/oq0jq2uIHNpSwwJCnjYSZa8sjcavPrOm3zygFfGnPg1hoyBQIV0AjEJHsZAQz4wPaIrqViENoekybTwn4qlZ97ZOq8axnbZZ6XsBaVn/Qq7zmNbNjSJW/Meu+ii0xmjt5B/UAtVCwoSN+PyHuns9i7TJgLbZe+8bNU1Tg7vhcsW+wwW/ua5CkYbm2SIAADq+uOwDoksXFnH+2lYCOhCZre+on+tQbTbbPRB4Mt5e8krVIAotHc0oAhmj0hrYxhIT+xmnpt6Cla43l2tvB0VwFPJiKK3ykWNriEZQl/8Jae4g4ru31gBVmyF3Xc3Gur5J1nqwcELgo3/TqwrUVpumdqzRtxfAqkA/wWe03PDtW3CbRxzlou99+9/333wMEkXtebGveJ7keiOKj0QhMNL1yP8zPz+Dn8gEOHxGTdQZBp3DhEPa9Q9jdrw7BvgHuD1QSxyIf7I32nu+O9vbWGZa9FAtH9mzByHxnz9SDiiTnVpWnDl6YfruxF5vX8V6w0qK0Wo5xYyWOPeMSEVZlfJ187BwugVwbqjJTz2tM1R8RrtxGm1aFrySb8Fj+RpzQz5G4jE5tL8vZki7blgn3vjrdaWseGS+oRxShJLUCkBd3Frb1GTSm7+uvLN0Du7bNlfUuEXTptezcd1V/dqK5mJVL21DvYNglQ+sECv1QUEKtIPmokymIKmoBhWzFgYkMIlztbu78jv84JQyYjo6oC08TFrj3UZqIfME5aruhn/9+tjhY0micnKXtDou0/Jv1WtQEohukzzGWWryppsy995WGtGBrWxeTan4uEvFod3XhHV41QrFkua3hiFTEvF6CJeP+h8Bw4Ddlp8svuCn89Y6vfBp2ftf/WovMmydcL6G378WbORma7L+xXXY+F4/mWJjxJJlejM9xQvq2JbvTj+K07fA858EU3wN3fi//WO0g4jEsK1vzl/9INsvR4bRHVcabO6mHtrduPuCewT2Wg1uOrW+Wqv90T3HZlnvqHselAEQTb+KRNhSBOeU1XkiO3XKbPOg42IVE2WMtoMEYaBS8fwYr6jPLbF/JsdIJKTqHdi85aKaMYfzwGHL/YwajXPWUmb19DOfs8UuDaRLJYL4C26UdxbOg6/r4LYbsA9pSRv5l+IRGKfDikEjdDhrAzUoW0cYUCddKcGaG2NVWQHN6KPZ77k75KRweSBzegT50ORYXX/hYqA0cC0ob6jsUC9x9pNuCwWz4A9Ohh3IOr5pDBbxrB+ICT9OhOUxOPeMJCylA4bMIqewZzyH94GoA3jWXno88yJmA06767H+ElOAeDysKx3/uoVmYh4e4P+fw4R7dYX0WyRtROeJ9Rgc8yfrgUZQd/D8y/H/7jKfy6kbM7T/0z0EkwG+YwrvdUabR/PEPE+jDA49yzbF1Ma7DgVM7t7seNvuGPnotcLlOHemzvdFH60S0uqEN63fEf6DSzPi5Ptyrlp8mWY8hJEn/LECO6yho48CvsMAa1VN4AJeBuOKZ4Os0YMp2rNjGh/s9cxh8L3zeI6Sf76hee4xjLO6MlxHtMSIvYTEOzjaY9xZyqxq/njST0APDDBPtj33Qlu9weQ6OPlxOupyF3FSPc1N8dGWDyDvnbhGaFE4Q/adMqmmX00IzPzSb0S92VzJkPAJWMac1Vp8tvopSkzRzX7VmLCmHvJzM+hwEl6Y5lHHObzRuDXgZa8BA8KWIEoUxWBCFAPCGeBHc2+3rsXp9vWMqrltrEwzEFYTl+OfsyZii67RmjXMOy5U5LG3r+Q9IXRfKoLagdi95GEq6p2fOBpqcMTNwIeJxflVPq9et/rWMohZfrIX1rBF21YpBofJkdkWxRyvXRmrUtpC35PC81PFvyfkVMWz1q4ynU7+USQVOIfrAH5O1/vp8WknMsNlbusgaZEr3cgl6y9GJ6zTdvZ6z0+MWnbuN6LdLFIAYmn0BIq6776QQbV6trrFzSFe5dJveo+bZtlPma0E4rnqv6DI1N4u02HX2S+u/j55J6+GC3WBTLPkhTsfn0ZS/cvSvHP3JcXRzLK78AU4m9Amz7Q7Agb25eYtYpkuCPczTJENQxbW9Aj73mWXau0k1wKoN+VR65S/rOBuaB2tseZFaj1kLLtxWVqPy1QE8lpfoR8WzV1bBvbu7IG2urzgeAEdPv0uymwHYvQym+0J1vHEqVtPPvQN6EA/dx3syPodaHujU9e8zTwys+3ERVSwyiRoJbDlAfq1iMAUmKieA63Ahgkz4EXo2S1l3fnf/PG1LPem9ZdoJdZVbdixAirjVN21BzXZP1c4XyhvN5twg7cD6JUXkyo1+4EtUmkarO/6g9Np3DKPEh9W6lJ9HycRk2vAb5sEYb48Mj2wajK68+3UyOaH2V7TNOwP7gxLg8uwgauVSs7ob86iD3vdHCDcECEK9gz1EBqrPpA4v5Cws+FFRmBPbmvGPbG802u45w0rGYyXWGldzIG/bBqBuZIqnKeUTGZsgzfJaQXLl9iFsBDuhMdiXMtK2Iez+QJ/zPkooV9BQn4mPIijopU1NeUYAhFHkjh1Zw2qPNe0jEfRGi8kLsZLTkR3WVXkc79EVNMdQDjs9drvhAMKzqflgY42ZUBcbmQV1UJ0BppK+0upVpw68qlmj1wtoF1E2AEI9g/QdbOv04h37/tvRbuVOiTh8gP4hYXV77w+mA5ir3HSOOaTc48Ah4oJHFRYSJzl6KuqznJQyS5S0InZWuMl8NVHfDrN8lHvCArXZjIYw7ZAbvyVJb6L3DuXg+7GyVaNCeDYrV0fJZEd8BBtRz+PW6T2cJ1i8i2jzoohumGgrTsJNEcpc9dmtVBKxrzUwmLgFTDuZikjGACRnMW9hF/ssULd9lsP/QWH4LYI0sjOZU3qx3VF/NBrZnlJ8NMBD0zz5NMA15ShaDBH6l+MLgUsseRLqVwbzcRCHrQNqAQx4K+5gXwbgH0tr/peLd2/ZVhILhwyk6PwRi20kBABNtBOo21X6Obr4yZwfwJjwyKym4ZxfD5QAYpOLcHDLo0JDz3Ts6XJ5T53zED0xAXkRQd1sLDJJmQ+FxXU/cXIhXV9JXlxCrjsLhK4guEIrFYmvlPRWboHG4IhyXe3pK8pspay2XgeLhbKyifbnJjzGffwPInCo216/l6vbJsCtZn3UZBXdlHjQ/ZgxYrl6A26XWhhMVa91QX/U4WzEIbtYFc6o3momBTOSx25npxA1HC6GOrW8ketiEFpXYMqmskZpBMSkK/ovi0aHUMjN5aVNKBd4RSmbejc7+aRFbPui2icQ6oao3f7k+qm/FLeanmCJB8GW5P8/e+++3Lax7Qm/ShdraizlkNTNchyd2TOlSHKivW1LI8nJPidJySDQJBGBAIMGJTMpV52HmH++1ztP8tVaq28AGjeSkp1sT03tE4uNvve6r9/Ck5gnEJhCzlz7D1DeQBAAT2L949dFMCFgaJhWr997CLOYUJbveRwkKe6xWKQEdAQAzXgDQ3ErQx6tKVoBPaCcOV3gJU/yp3CkOqYheHbriVu5qY41rUP3gBWvRvbkl06q56eJEIMknchWeWMqu3iIwVIWR8s6EniNn3Z0hNKkPncCmDcy4KTLsVypBzXsYrzZuQBxErICCywWi25ZfsYwE13ifnGnu9FCnLP2JiZWoNGfmCpmUBcgu03SCVC+cqBt7mdntIu+HXXkEXG/+j0ehFke4BV/QKy3eZhy8YkiKegN7fyB/3cd1577Xl/x++SOGw5ON0ndWghf5wFdWvqp3qVXeXUbaIRx4z2y04w28cm9ZTrSYLUgGKUOVdB39MZyq1lrb9mPSXp3Dl90OzNrQo99YCunrkB1jknMeRfj/iMwFb1VNQBxxfNjUAav8vRsVqHOryW3+FGP8FcwTHdPwGiIx6wyMChOkXmCMKq9AKx5OJ37kD8AFwgjGZeZzGaLWBUXxEOhQm/9XpB640y1imQxTNxkDPL8hSBcE6gJUTeLKIEBY2A7cDGn4QQ6X6SQWIyd2DfftcwwFlm68HVMXjlS/0OY3fqQIJuGbcytVuTLykJ6sODtGexaDNXQ4p0/HuT7cSPnVMb7Vz/qXMi/edD19FgH/9c9Zwc11s/5samw2abPKZa/+hRkA6/EQOtj+Vfd/seVtjd9DJ88aP6zp8LNcfnYSa8PEsWC02ncWnWnRlHi36m/69l5D14II99OoSwvTCXB6ftQJzSSEfyPzwEcNo16juD44LPnEC7DDdjf1wqI13UOP1lYfQXv2gm4Hyo9t5V0+sa7s/mT/t4RV5Em97zP4BYL3md4tfuUuEvXDIKtNX1l7wShi+AdF5hBhIgnaFhO8loK4HcvJlNZVj0Kx9xf+i5LMUwvWI1In8qVUUGFf3UabYvP+sxLErR9m6pokEcXQ1JfLEiLVwP/QBcDSVFVBVLH48KLgl6+tnRrnWzQDb9A7U/tpuGbJ2h14FTy9e/g8uCzeaa0fN1F36qXgnuJZpx0EaMZx5s4HlbZEnCmp9FZCrJW8Kd4ZF3PH/d0kKl0gNZnTGdB3zmPVjvUqCX4c9ZFJkGYKcxcaHmMx9Ykq0+PLBWN9hTjC6lFxupgRjF7WI3F4dhGq4LiTMXr+1MusrQBbD+3hy2tK2YLc+aVp6DleDwFOa5E1itzMEW0mDh/aBLVGy0J1dUQKdk/uM2SJBcH2EKCDEKx8rfiLoyi25SPO363stQailvtUXD5P0NxKx9VR1diiTwZ8rvzh/5vYE0q6am1cEgX2TAc3UG5QhAggXmRbmEKY42V5Gf3Y9WPPs6RtfvQM31gJZ8+BnvJQLLyO6V1a2Z1Ir9tHauopjQOY6oVVpmS/0aWclHPTaICVIaqmb51tBpIwVSeSNZ2qaGwVBapQGBX4ZHWFfjcJdF0AZMs0Sv6c7co39KrWCWSqDaESHMZYisqomg9do3hL2dxFnaIMsJvJKZY5XXqCKBlrk+XrAujFcx5SiFk9sLxUMy9BNS/9T0yXQUIFefSJDuYU12udKa2AGFOtW1oE53pJ5Eeyn6UBjtc1Vn3qwUNOnunq34KtjDXL7JsT6sU3FbK32cTSdQ29GkVerfzB17hjn4N9yMhn4bzhTShGTW8gEqqpnCNKumaXN3jIPZ2cUK4t0w7IFy7Vu+EWHXLmn0Qj7dnhTvYXUWWylmNjmy3WJPZdlGL39gT+wz1Ymtbqpmb1UjWto28MB6cxZMoFFOVK4e1bo0+J2GlecAJKKOe1XVQk60t/Uw43SdQjKVOeNtg8/yonFstGuYsG7egedfabxcZFAMlVxQG6qL/61buFtaW6aYiy4mu5hVaw6G0qkqvjmB1h5TsQGe5bFBE2ZxZAEnXioiGbrrigjWEhjVyQBV5qKe4Txs4vCKWoHuPihEI7v2x+f5qW/SnDfR9VAq8CRd3Swrt+LIdxXZ8+IWCf6HgmoLzIPSAfvtROBdO0y20qKhL7Hv4MiAbG1ox6KRKfoMGJ/R7G+wlzHKotJZ+6wXsikhGJYzOuxjk9iRVZtdDNxKqNC1f8/Sep+wsTZPUXbmZ8Ild21bJ9spbh0xP7xX7NRk5udmfbbOehHs6DyBLvZjmCMWyMPiq3SW+xsbMfA/qRyAc9WigHXZwo9v+KJv+KQ6nYSNnSbqsKHqBv7n0aPih0nTtRZFuQYqgqlTAxpjzDDogVAbyJqT+gV49SdKqvDAzWPN24wQAUMB8tCHZIeUCUo+7UO58BxX6FB2A8yc6h2K/tZZFsB6SstshzLkvJcQu3yBjgbxN+wsbMisH9pBk4L2D1iCp+lO4AXQXhOZSa0E9yN9ZkHAq/j717rmVK0dXmQme3od+ncSfeZPbvQ3ANFE/tqfDm9zub6jj/WLHBxvq+KDY8fMNdfy82PHhhjo+LHb8YkMdvyh2/PWGOv662PHLDXX8stjxNxvq+Jtix3u7m3ohu6WuN/b4Sq9vb1PPby/3/hT32kDnuqvNgCjWoBUqbvZIsIiXGvSQyW6dEh3xviPMgHWapB0CyHEQMMkzy9AnScqN6IHFTf0kvuepoLmosqoYF5LMPDDpQ/kk/iEDxHrBxvi/IJNMvTiA+LiABwstNAx/jn+O3wlOt8AEFuOdQHeBEXAG4DoQnEHa6YTHPA19FkLRER3bwZbJgvleDCXNZPHEJZsv0nki+NHP8YC9RmeON58f0RB/kyj3YdAnNvA3CcQfBtD8e+5F2dT3Uq7az72s8AGPkQvrb84GkMPAU19/Q85HbKA+StKAS/TCArRGELxRR9Gm2Ls8GC8IimDUn7eYVoIfJWmCEHuqBLgylg1eMq6uLwMcLQ2EVGeCOT497fV77y5Pj2/Oev3e6dnrM/yPtxdvz8qYOT9OPRB/AKmQkGcIJ4BmqUrUNFUGkfY4ZglJTy2iVeg5+WaMazXnKRw7ioCUnTv6l/LFK7jLXAQJ1i+JUJ5+1d3bXGwTgLOYRZaDnBrAW6CqYo8yegRUrwDKvxSQ9Fa6X6pwM3b5MbexTa+GPlQf0DUkQbnx4+9KJDTStXPYHtsCWkr5G+wBHkAIG+nFYlsqUrf7a46xrzo6WLOjA9XR8zU7eq46Olyzo0PV0Ys1O3qhOvp6zY6+Vh29XLOjl6qjb9bs6BvV0d7uupd1V3e19r3f012te71RpjWybGNnJygmaImVbfHhZNhnP/dAhPq5B/81T/mYpzz2Of1bpVL+3NtuqrFW4BzaAs7UR2wLOIhcyXZjdHQ85qnDQG7JsMQkipyUIwyPRZxJQETJUtPuLdnJEYNOCGKPmoN/ZZ4ms3kL6nihbGQkgDH6joRKhDzUXVbb9aU8/QDukR7hf5cQXBwiNcLGBhLFpcq0p1BeFlEWziNLzNYGncxTRh2mHDRDdnL87ub84u0RuwEp5CGMIjUSmgnVt4bpJSnIxWlDmI1Eg+liGtTipwSBeSQBVEHMNFvFjDY2K0yt91eV0b7Y3L7Y3L7Y3L7Y3FazudWYkBTLy7m0qv2yZR5IjlmnWelKVlazopGIvo2WiF5WFZrc0TKyZAqufmO86NFsGfIjrcl1kebkt/qDp3RZPbmfqQponJrlip1ugpOu7nGvuRZtLLftBM1TS8YsvzP5a4dXZkmBHR/aY0qAsleHvoHvBLUGxwl8uZ4bv55urjBFO3lLvkBGdeZPuSMx9QT+ysIxZgkU9iIUzLv3Qgy9cySWYmPqvF0ciemW5r/JC9sIRJTcEWKRvDfOYIVwxkXmzeYdyfGh6x5bq13EehulxdA6yrqIn/JZypCfShW38DtbYEau4DMPkj+YCGdh5AFq0pDlhBPlz8kSFntpmjwo99oj+IsCPg7jJ3EPVUZCtaa2cj+VS+ZfwMdTlouEn6T2g6GKdeWrp+8Wwy/Y1u5gT9munSsqRNh4E0ZFWGTWknH5lAGNnQb3ajN5td272pBdbZmuNjVX246rjcHV1t0ac22N+bXGnPqxKaez0Wj5xKLuX9KC9BRePlJVSz40+nMjDZBUD1vjY9QMRFk7e+3dXmXjVltnVtl61dZ7VTZPtXVXle1Pbf1TZQNTW4dU2YLU1gNVNhG1dTmVbUBtfUxlI09rp5LDitPai+Qw07R2Gzlinzr4iZzBTb0smd/eVZjIpUNmD2rAhjHVgN2z6sHu7e6W2G6pHKwUEUwp2EaniVRlQb5M/LTGenRxclU2HV2cXEEwP9NA4hUmJFAUqA2hpslpJmMA6JadDNkVTllgjwrvs688QBDUwT9kVIlP+8MepjyGtkBnMcdWKBwcd8LchZ/+HZMPmsW4/Nrsea8j0tkEF4VNvXUWiyzR4DaSm5qvLqjVoNxASU/6i9m/ngXCCTzWCxE5tewFTVMAH7KOHpXfCb9tGxttvEBz9CbKOVCkP4YIdYgsgvZK+mRbeCf0MlZ3ulrXai1RpjjE35MRpWZDKIzRH1cFQHV0rpGg7O4pjcyDn9SV6iV+euuN/L39A3MTj3JXwD7UvUN1NL2zN5evL/7jzdnbG3b83dXZGfwXaH3o7jybzaNkCSly7HiSckyWg5fJQcXiAQvjLGEjnj1wHg+H8E7t8/GTeBwG4D/vHe0Ovzns9yIvnizQetTjcfEIevu7+88Hu3uDvcObvd2jg92j3d3/7BX3sthq/2jv8D97NbIiJKgoOXHAlBgIb+z8VBZma5W4Yn2cpGwm4a5y4qTDEqXe8uOWZCxpU1PODBWRHAT0cPD7Awmnfcc2CorM9nwQQCa/xTtSCbIlaz02wx3B7JEIRUK59fOiOY7GwIyJU0IqEFpPn2kiXw5WcJnPEj+t4Ic7QfIQR4kX7PwBs23FH0/lJzg3wzkKxl+7kUVwFIcMY3bvpWGyEPLSCZApUh6EKWBrQ/hBgkcD3yu1QU2Wvbt67bAey18v/PRKz6odO6RZgfXGDFLNDBM/49lAZCn3Zk6mWKZrozD2KFyz35tyL8Cr/gcED8IAgxv8rqQ0nb85o3TtkQf4yElsdgBHqsXk0p2fhgKKtFGnJf0OC+EhIcPULtgCCQvZpu/XPJ6Q7bUkJnImwt85HPRomaF1rrpD6PJgd7/cz5W8EE23oZfb1teJhHAvm7CmSZoNovCe42eoz8kRrHtgXYEWZ7tIwzqCmyexfTpQTfEQE3sRCyrPzAOzqgZa3ER8V9Dlrc1tT8AJ05seNfzRtu4+PmWvpephHGahF8mTVTmZTqy6jvOwaDmxBFkCdR6MEdkshHSJyEHbX+Ghwmarcz5i76GP92wL4XWQ2G/32Xvo8T3bIviBBUgXpBfAI/WTJA0gIYMLaDoPxtAS7RSIGnV5+ooaIueIvCVPoZ2a13u2pf6TLeYwCbx3/gLIQAULuUdo79vET/NMpNL5UmIbtZ4XkiwMKNPUaqxxm6z76daBTq5W88Ck3KOde3wfTK3X5WNejdIalPril7ykq+Xa5M5qhMJvTxsM1UFJHuzyrZSO6pLa6jtBlwmalYxji9EsBFwX3RQOq8DzrXhL0nQDniFNhy0XfaR0gvRfqpM45h5cebts/eXpK9Fn4Qx0KmoqfC+OrYsrjJ7tKZqQQeg4pOSMOGTlUPpECmix1vRoG8s3Sja58NNTOUQroCpFklRZxcdxSrdRnN/F4W8LjpMBvSMLxyFP63XoRnXYUD5dxKRRywYqKHewVSVttd2FWfN4ErrQHl08gdrima+twdNtpY4eUUfmIgtn2LlRc1cc5Ex1VdSYq5XlX5PR7YuvX36za+vL+ohzx4dXGF7zgHTP3b2eORxomqUO/bqNauvegkLr54fY+tO4Q85jsRiPQx/8rMxikZrs2RnpT1KOQ53MIo0cJTnsX5vpxdVrkOauDxiIQ0rk1pQ9SxTV7Fl3qDfNsrk42tmRfxn6yWxH3ZAhCERdn38xcj5wkAN7AuXriBZtgvZuv3I0LfscSipar+aBj6YJ8tfyiiGufeDN57hk2VAAvx0oKrgi2coSoFx24Sj9qIIg4iiEWaZ1/bOZIv3lY7+nWOmqBkKC+hAl/sNno1xQfEWnmKMCppV66bQp4YMkhebhzpSYge2ZJ1hBfi6tQ1HTagnfF/dKwC/Ziy8W2XyRSVUNaYBl1Kc5f/zYsDaUfpqXdkoyE0g+OnklSWcKV74JV8qi+erocvuquQos9yNRL1DqbkcL/463MFpfHzBqCrdXYOa2sQ2ZizlbDuCBmHx1NQ5kF4UfWo0DOiw1xy13DQNCL5CDnWo/UUmjmafhfRjxCQdxmZi+S1q+VM2KsZB4PrqTQEeNlB5a7EXL3yFJFO5/kso6yVqOtaqP6N4YgawNGQ0joJpPksZ8OaAgIdOyT5V95mkSLHzsFfaRk8wMyeEJ1BMAe7WwvsLIJiU+W2+GhmXjCLB9pO6prNgU2UIOpHkShf5yME5DHgfRkpEY7YERaBHiLZOmFuEn9+BIh0mOo+RBfq7XGSUTMaTkIl0UAkLvYnZ8PqB0VnhbaQiZp1DJA7/XFo2UzyPP53p72K+LYAK7igv86qtrMEm9BgiGo6++YsrPuL+729/d3WX+1MPHmwq2FUGd8NQ6lZT/imLgtuzq0lwn6OuKmLJg7/2pl723hIMh+xEcNxR99t5ihe/7zItEompECPYeb0LuWxrrbZJxGAQ78vD+QGeFi9PXhhgsxp2DRMAXCR6KHE9/Jth7vfe32LEIxXvjhkTq4grUhVtoXkIrvGl9xmocZisLG5GGzOujHpW/RXu4VXIZoiTEgSr0SNf3Vt/asiRl9ezOO3QlGiIAhF72g1fQJSx/UDmeTPvKd21feYkB3fMUEu+Kr9LEm1kLXzm+LpPm6XrKbA7YDg3QK26/bRjtZvYNDabdNq+gxprN0cF0JtFVbZQ5/BYO2nnkaTwUOS/4B72/HqaoBnCFk7QLOGWJ1825H45Dn82nqQfeniQF0RyA4YR2nxGvzl3oGmkGaPg0iQJ8BYGnDjtY+FZJ1JKcc6X65wGjpNU8OUcdu/iGmi9MgWlwa1uh+xxX6JZDOdBGcUlXdiy6C9uonOr8g895IMhXQdg8jx0yB/yh0c7+A5L2xDCggsv0aQB2W2NB3NiBClkieRRnW7r+UThm9hHAaqAUZBjISIZOKqLcHZw02vkqRlQzKo2GnLPDUOenVscPhp1bs+5ObUuPU0kttyTU9fpYsvBWynKyQHES3yr5zeFgKBHhkMtLx/07EB9RZ8Q/eVF0xApDkvSoRuyz4oAf+71fF2kogtBvojTvrgeveADsKa+sWn8vGcesrgsUIF2gMtXXvngXnWmJA6Ac7JSfB1KullZRhfP8aY6FVZSjsxflexAVmt7tAPMdoOxYBtN8/YZhV1K/lxhRJAtV6ylALqSGQko0FpWMxQNBIBTVEwpXLUa0SS38+HwwTx4wVoV6kNgHD3zETKlrtwYPwlrKpzwWYCJRn2cJQ0KERjB6E6YznTdh7PjZQ4KbII4YUPp7rt5lqrsE6kyWn9ev35TmS2OceIIPA37/TLDjczbxMv7gLYfskqdjTpqx1KBUCe8+oi4M8BmE8YTUoYkH8gb6AGh+8J/83pIV4FwdroGJ3JRjOoZWlTKxKVNfPpZfwFyMBoI95dZc6Cup4IWZRzYfoGf6HxtNzoAgeJddDvOOqirAzxcjKDzCg1Mvq8hZcobXffxYFqySRepjRhD5hNROUHkY2sL6h5+L08BHjX3Rk7ZPGpqg0w9u4U0rQRpagVwpH9Gcp2Cd6QojYUQgCl1HQ0MUkoioIvAfWdSRsfM1RvG6R0LFH+NxOFmkSlP7DBME4CkpGkg1G+ehT+ZkeYJAa8ytWghOaDuvX79poRVBvpkid0AR3XcMi/BwL0C3laSoz4SisZ6iU5pjYfBZ+yte4l1SBjIrASuNDGwzbHEyzwbPk+b7XyhO8MAhkjnmD2jX9L2Az0K/rJUU3gn4J+ip5OaAfULdtMXsqpRo1uwDzHMyFKWSWMD29ioC2g93c2HvRmY5TWZe2IqUVoa7xGDKoRkBsSZzjgCDDnWNlt4NDXZGHeVHIHlBygpIcmfIGRdtsuLgmlgfVFDLCtvHvrWru8ODj/jTDdQ9bXOgytSHhVLJxAqzUXzbvjH7u89flplJ1fNUwmQuVDuMnT1Li7+JHGzo+xobIlNS3bGtBO4AzL9CftouP/Mq0VIeY1G4lKtwxoq4xEvldVGrxyvy7uq1IyPXT725NBlrkNbczmlxdE6RHhT3QTZeHefxTvDxInJKeVp685MoIqtM/nMtcVtCaYROv9R7iFA0FIsRjG5BdCnrOc2RVl6JZTXhmQyPFK/SZPYujdoFop7o7o1gaPmT7F39XBJvWzlXSdjCKM1q+a6kx6J9H9uumTeB3Efd1caIl9wRL8GGIAUWMjtOw8k0CifTTjVyqgYxnZXGWQ9Mzxsli4wC2y1sztWExyRV5afx8jFa7FMLjk1FMgQVyUCplgWL1LL85ZH2niYqYwFvviRP4l87mIXyEcalg4fPQULBYwGnKxLXnIfYpqqOd9RoiM8H7uU8mnmW5nwXLbqXkpGeqNWPQ1gtP+MWQ0yMASNHvrlzCGAFyAm6DSIFzzwnIRv5MvZmoe/au9KYN+GMJ4tWFTioJQgagvtJHEivsT28PdTBLm4f8rWOR+S6SywK4zu0YcgenYeFv92ALazNkspJn6p3FLrxTKxhDhUsZ7fQFkMMdGiLwjxuw2JOqCHeq0VoXVyrXwxOtUWEattehQBWGVTtkr7Wj6vOE1unQENNvkRXa9gUK8DanJsSQ9sKzic5kypCsQ5Exudani2LRURnwBdqNcN07CQGkz0mdZqOlLDbt2ydYUyMBY3siHyrMGAFmcX6MiYD9ApipPY0w1gggR6y84B7bikczKbW2Ch/LzgLwiicoHQexvdgMJmQcdFRJJhWc2X2ofnKqcZWntyj1STAgc7bx2Cb0EXjgtaHvLKl0e6hLMtXEEO9TeMQ86SFNE8ZP0TuGdiL1f8wubVy4r0YrlTUy82j6qLr+I+EPHTIXiLvAYK6fB6gjofZs/I+4vNZzKE4JTtJFmkG3iC6ydRO+pMoRj3j8Mdf+j29pKPeP/jSLFe65rHZajJxruC1JSA/Ie5KV8uq9TjyBtXNJPzbZVLLSf4NRVQrZlrcZTLHfuy3tcseR6FHYlGup60xuf/veRwCLdqufX/KMjn2BCxaX/N5muTdmvqXitX8tvAigIOK+D2P2IBBh2zrt0Xo3233GX3NtkZe5MU+D7b7QH/ZVo704kwTDDm9rjyWiljqv19fvGV0mBSgKUP8lHGJJkmdd5ZX1PdVEBtun2RmxnVCURQ3shlyo8AVM0/cAWs8P7VsPaMkw/HiwEsD2haTTY2iGxrdlPieci/CJAtZMhmDinN7pgA9OCYgWUMLHZOAHgGR56PRsuwuheGPz5lYxmBzDZ2OxxV54mbBPrrnIuV2ZgUoj3QRx91xPOSqk3H+yGAOHQjJhUqWTM1j5g2hAY10w7k5M83fN8nSy4CmLa1hZx+4v0Ajs7KHERRPfjCSukvk3V0u51THXOibqT5tH45Y6SKujFf6aAkTGzV21nqsRRzO567gea08VE+qyMsiJZ0zXYYjkH4GRQ4+1TpwAKSBzS6gE5NaM4cyZXEGhl4Iwtzd3bYy7I5XTbC7AfrSgEKzZuetUWjK4rITikaSIYiyBKIVgISQzCnqPITAdxaF3igk8cF7sKRuoCYVIrfsrPhxvvdx4gN5jBmsAqMrUN+LuJeyMciyEA1GMpQXQTBZNgVbludjYp/sti+zeaacnb1jEfcCAvqYLCIIgF0yPh5T7I/CS51CJBI79jP2MAWgCPjDu2uolScA8RIoQpIOhIp+9ebzNPGgyD0qBZrU/KRJQe/snerxHPYVVlcScNFRf7aAt+DF7F0cJjGFDx1DpNvDNMSwrxknGJ9xkqKeyiCNpG82CCQAlobibkCgHGpyIFUdn6tlg2OooMLIh+fMl/PCAUQnWRS7tLAjiQ/7Sh0LOzat9QPFNcqdCOOMAnsFy0KMoTI3QQOKwEqYB9KLwDQJ0Il+AQSAP+fEbVKEwHIWOWkEVHI12j96Xo+nZLREyc/OTylM+2lyTsuOEmc4cV78elr0pSoTSFkg04NLD3lnqCULmL0gycSYg9Qg29tTwCqOYmW0p6ryF5qoYf+Y20AHqafmxt+o0Ly62Rul9RDzvyI0xWV1oZ8k/nFR0R6lYF0T3gvuUXO1ILDRZ47xQdIQrkzujaZDZFQquaAmVlM59U3OQBQqqyJF+c/mUQjzYoSd7VCpOmhT109mX6xwy1d4APMxSmsL0mVnUxZxpUTlxqoM5HSmlld0UCldFjv5Ng35GDM20nlmgbcZP39DiGgrGe8S+qCTg5RhvXBrGIqFap4wxWDphSNHlbykq+pZVDyzJPOi9vFsN9DcgadqkohaAgYqU6eOKW3B6AqwgWFLvvcqSUdhEPAYv+nAA5tsoTlEZ6AthmSZdPfPMND0Mg1RCS/eBZP5/X+JIrcPMihHFRhXacojClTPU3twCcdTpKlWFndVimAhslMTWwzuzBlQZYu2IZ7dqluqbD9VIxNhvHNEkwJzUxs6rr7P73gySb35NPRZJD8iDpT4XoRX3eq6Mfh0BZTkuhhVBZK8wdhT2YMdtYHRB8Vd3Fj8qTWg7NMOPrWHFJmXZicQIdCK7jviLL00I2KPzgHoSf5TUQZC8gjWGOQsDpqHwJVcduJiTavRPNG9ojUHy62qbih5Z246RyCFNhyqI8pWXQI7arUhIFHJ4DphEagMeEWkYTNJO7tAZDGZtpL4qxA8DfRNJVAENtKxsPkgWP0xJPKxSXjPY0RFrY6NRdBBKVNr2q6k7b7ynQoEpKQvKec3A5aDQGpi6gFKgR55ymeUk6wjq5RXqSxlg7FYFkU50cttIXHbsbCEN1netc86GnZFw2q/Z8oTXbtrzrRKiaoSVeuypZrFy4826hvEojlmt1rBEhvPVEYMf2I/+mMFiDrjQ2sJMISBupKPJHrV2EFTiJY1yh9t8lhqxA855uPKH58k90XrSVLZzA+3rtyBS1L8jYg8CgZgVh5nCgkDP11b/KgZa8THCUYCWINtQhBxDGkkBPcCH3NE1zLXlkq4u1bDqqKJpX5ZaAoq44z0FlNazBQgaimtIJETrgiNpcj4LC+jvA6FARdCPVB+7gjNQNwoMHLgdvsmYVF9BAn1XpRMWMBTRN/GFxUkvhj6sq2enwP/aVGIYwVZCMgXIpLkkaXEIh17MKJYQEgFTUuNwabJjMPFKEsoUSiya7PE1iGuZmmpDFF5tEKk1vmtJqFU5GKTybuJKDp+D/2KH6YpHzt/SNIgl56uJYpCdC66HyQQvT0LOaYcQfX3y8dSdK/aq1+sQN27MIrcWW30Sz44l2pCSCgC/LZsV6A2HhibJwPhJ3Me5L6Aq8zpP9kD/M8oB4V4H3pMTguCqJIIZJMoiScCY8sXEikAGziCZHF0ysC9lvNrxifGlgqdeIOXM1pMul2umjCUeBERhrzKL6kL7ChUVGxi9bXZVR/7vdEiDnLiul5waVb3PBX5p2EJyN0rA7aRmMMYA/QqpOJjQyQJjko+iK6uRfrgG8fliRYT5kVQTARyE0NBIQrIU5N00sL2ircPq56G8kE/ioAtSYfqqyRru29lyVKAs5V9zcJYlbsgMVn9a//wBVxn5wNwOEIGwhtzBs2H7HiRJQODw4FMMcYYhDFLZmGWcUTfswbb23/ZJaGRfCbW39jW3mCfCWDpsc8xW9jufXd3t+65lUwUYJQh8maJPoCEA/UN6jbtxeHhwYvur7cckTMREqmF4I6kpxEjOWVyRJKITH7cIa8yHYVZ6lmV7dkWuTH6LAp9HgveZzzzhxi1BGVTmh12OhqXaAzBc3sxWo6hAwxU9iKU/zUXyDQD8QT7X3Bt/vfO/wKf/P9G+6sXB6Pkg2xBpUwQ9Elem3PaRzQfVwoJOQhF8vZXPhz8vUW4ZySz0wFJOowLK1HzXA7Z9T/OX78ezgImMyLSeynRYYBAkmT561V4DYd7+/XX1XHjqp5++UVXP7Lyk9kwF5JLqgLMyI9vZfeWNQAp2lgS0M4fcIucgdoOOegKUEXc4g/+BOeEtllFADASmyyIdHSjJQvBYokUTykLikaoz7BktchXQSyLPMB4KkQdl4QumQ2EnG4w3rklpaewF9qCfCWDzsynO8WX78z6ZYNkfX2yTWvDTpxyVO2WqObg+kSKfNtlQ+mTHubdIhlv+6Fq3omNkHRu8RBbO4DQy2i53UXqdE+NvrZgeyG6SdNOobCfLV7D0gTRdZKYX4wplLKGKaQJZm8SlyuxBPy1xvcLM8Hsyiou2Yox4avrE/8pTaFS+3Czq5o3WKV63FZ5uAsfEB1utZ2wL7e1y2raWdhQ3FnTVadN6Ly2X3TMet20pOIKFBdveznjga4t9URylbHtSP1BP446teiNdBXA0o0XoTIMUpJUE/7Y7z3fd6g5V6DVIxqsBIjlAdvy4iRezqBiIQQKiO2a4El5qJsMnyRqjOu0mYkzVlCxfHAQNfL3dxj7WG/nkG2q7RzA44m/owlWYa3K6gSIRy6r3g/ZD0S+EdYd1J8w9lNONsYyw6evam0clYxfjvjFxvFoNg65w39iG0czkcjbN+rsIpBaG4Www09CGK4NRQBQvjn5NH5pMMC8ohdpvtigAaadiWVFy8lb/kCL3UqxQqkw+mTRiNFkIilob5/2LVYJRfVynzYlyIoXCG1WEPGylPMhuwAuliWQmHPPyWYHHFOZIMjwsIj9qRdPePDvYBoK2E+/kBd3ltzzfNOntit8UfZXUfbhumABqgbmf4qt6pn/dTLOBtRdKwmg4PGIEwa2LAAonM8hsawUNeiqLwKjrcb16dun4PpqpLLj2LC5z46BfQLWJK9ivaxaMk/t8A+Q5tHSSnWGjeW9A8LnKtoBLTxjTPViZXClAkVA3tAPjh2Qs12aV9NFjLmeaLG3dJWKx0ASr/To6ciDJn8eLRhXd0MraL7z59YCcot/7MufFXG9zE+o7zul4RaaI+qLfa1CrmQ2aMNZGph8vWYMa5l6+4cv3D+Fv/NbKnrucnTXIzHmNNpCbXC5558LYfkkxERSBbuON+3Kqpl6uRyECYbplLMiMPVNEoGiD0OCyeCe6wkC9RiyN4mA+sNRBJGNYposogDdekSPEWXLE4I6BBVCEK42pa9DBp0ac9ieeson1I5sYoxPjnKVQZuhCdaYyhE45aLxivTQixUyrgFd8RepSFKZMT33IKUpc2LnQhCOxfbbBeLgDAFLqrCOTZFAHTayGv15XKvBhkXRDYc0rGgigPygD9ktXZtW2zD1xO0sHyb9xMJYJS2kqlIF8lS6fA3BuDL/R4Ff7pZIVBk+U8Wubu0pcA09JbmxTXOqosgn+DmlfOjHzLaILp6fUhjDHIqJgbUUwu228wR7svLQMo16tATnUXuiKEWxllRRBYW7CaL8FYgfIRtQF+wai54SqNN0OUpDHYGwhbGh/wZTZv/GoFIQ3Lht4wxNPYRTVSeGCdUpjzimVMs6my5nKC6qg4JUzBP+XDIn/rQe1Y26QYU7z8MRW2FfjLaCdZNLxlRf1FsstMqSpKjqyG+Jns54Nk0CcYtwVWvsgYS+ot4I3BIfDEYE9M1zaecJsuAYKcE37xV6DG/Pb9WyZ1dR185M1o3qOUmzoNvAWvZL9Urachad6IFBZcBimunxYs7TIPGpiFmcZDLOvxSRC+1OE78AYJHMAV2Hs9OLk39iKZGIEg1lDexCvrRqLb1QMgzJK3xNFFsNyOSsCKfC1C3DCxnOqCoFooVQrArtihiyEy+WChoijN6HwQIgLmhoRCHE3CaFtWt+mKTJYu7ApZA7dax2qV2VMWpsMgWrqfw8GDuJfFk4G4Ux7D+WMrc6uI+DYTLn8YdZRE3FIAHZiKuxhw9JGphEsVk01LPqOPAKIK264AdIKnRBHheJR12gXNECRy/FhqhQK1hW/rjlPW2LvHVD5P6UjPL2cdXHuZyq3ZY+/YHyATMeIltBBJAU8ZtePF+tkIjMcwMGlXvB6NGkfpt5ObYb8NhPgMwX+vn4Ue9FUyyn8aPNFZmRxbV1dy09I/gblCSNFo7C023ANQljn245liqlPKF4ougMhhghnenYGX5D/RUpFwqpAmKVM2+y3QYDAhNO+z0kojAs7ZGUckryCG4ww3Am7PCj2qKjP8pRSxavzAtPH0v9/gCd2OeGaSn4awuoTe13y+Eosy0+nAwlf2BBOAOM1yTG6Or8cT6EQc4aWSHjnWNH2Biu1Tz8wCOkX1MO4OttO6DWdg9ShCKg31tFaKvPLEj8D7CIYJxH65B/L2wO9sqoV2MhKvOkageWZHoOaQGtbOQPaCcsnNAHVs78iGcPnMdygmWBofGLgqxgyQdESBKoV9Vnb1Rsa5bgDyQpfH/z5rX6C9kM0dTigqSSy5bzaVs9Ctp+4fwTcn4XTOey4yeXAJ7vuZCN0DufJAwLBbOtmfeB7R+++Xb7iWQGIuVemu3AtgyUMbCd2IAxh/0elhQqcSv8scW5utLYtcBGwQuJfCNZYX9w4GaKNQNdd5rNIkfwIYkokkxJdC5DmwD9oG4AeD19GiZHEuXfnczUUETz8OXlXl2Acx+BLkneVabS+2+2vmcXZl9RxNLdWgBqf60z7MrJqsv7OPnYBgr8FKiHu8SPbLRCkR9dSudTlvfB0RU9dHkBGsr/5L5vWwtIHXJ+cBMIjkePMQU1p+7Ivd/AmVMkQ+2JY5PPvqiTdRKw/3WXwG5K227723ey1IsFiPzwCgOewSwc4uSNbAaLLkRLwScs8uLJQuoweSWYfoftV22QNPEPmbH1w68z8AtH4R1UgdAtgVyqOqNjWcUULbx29QpAfGA0dQU4pxUzGMcZTAWtX5tJt/CoqjmZkQykweZOvCqFptBKzaGNpb2j40EfZSNXo7MFLOrceW2dX1+wFwffDPa2NQnCo2tW0U4Kx4wo+NhLKK44QF5HLndmnd3eHBc+UdnHR+v/dRampdK+0Td+kgTO/dGP9zlGWc64EBVnY575b+Qs2KYVK+9tB5cv1RBx4JI+/aL32i7aoa60e0t+fhKOro/f3Xx/e/72h+PXUKTFujUOreRSizwsgGpKsIsKcCvy/DuoCK9JqQTd+gTbetB2W5vAwuzVWDreprb+8uzqzfn19fnF29vTs7fnZ6c283oKi/BvDmjalua2xriTkgR/I+toBnmmSoFT4EwZgatGWjGpG4b14qkEMbK+AjscVovjmc3Ty8KAGt2FjVQpDmDckTExmD7KULFSKJCBSrolyxko7Ps1ZMrSCKhnCFi5ZJ5yMOnNwvq2mf7QZk+YI1El6dOgr60Ztw+zcq/4SUWC3HE9Nud/Xcfw2wUevLYPhW2FY3WQshwAD7Z7BSb9hXF9YVx/CcbljplYM2jXgQOTJ4z4VnM0NZ4UaKNy2jzj4hnZbyF5Skzp11zEGtVbWj3CWJmd4hksGQxpMkcntwTrkKgQHBjiUKnXE5e0l2A9XcEWDXxO/6OT3qt+4EobcE+cftY+E8PlyGvyXZIAKz+JkkXA7MUeX55bKu7e7u6/mW/7mCMM1Yp9swua4ffJqTIn4BiP/gQqNAkGNj8tMUK9FTe0pmYGaM/506nD1qLWYH9GYrhpVfj8xkgYeAfw9pJGTKbY1901aRkqoI8V+KL8G9AwmzeuWiHZfg7raMHuIr9/BrUYXkNRaqTkpC+68heR468pcjyNrqxz4D6B0qzJd0dVOccRa7L4WolXtipknw0X9THJTk9eZddDdj7O84O+aawwRBQvGuYngjHazUEuUqoxnkblDnSKO69yPkfJsMjG/05w9gy6eYYBRhLPTkZ+eBMxrOVkLinRng39vUFoHLJn8Sx7xrbe8kXqReyNBxDR3Ba4pK2UyjsoAGVZn7yTCWUBZGLnfs9hNHmHFKRU8Ru/YCL25mKauAoZk4+E4sx5Ohh7Plxm+mwG+Mq+QrMSmUlCkw8ekst4GiaBJU6qysVY0UAW0fDCaMlGC/+Oqz5UHVceqClS+csh+wE2n4ksSeV9Q9hpbZqRIJ0SIJ7GGHHfWwjOQoSuhqu75JmcGRYGwnqqGl/yIYyD5MFtqsFtvDbb1SykvsvtcBUmdZMEVAidbx06y7CwklDwbJtKoaK9w8I2a2hh7gS1EpsOEygCr2roDNkpPUCh4iToN1UVTlYa972IQ0l5NkvibDq0lUea/FkcPM3UuazIk594nDzkJjVJvXhBMPIb0GvVIwf+HkbLPNlSP5YmbMHpyzQC2ir1jgD/iyRvwtrPvduKjNhRGEVhPDkCoMgCldoRi5Ee3mXoddAstHkSRXjgo2mS3LF8L65sWeFua8VrIQWgblFbpUlTTVAHIQC7MU7uDBpcFybQpoqOPY06kvAEL7zpyPolu4TjXCTwevXJVEC1Q/FmV3NzIH028iLIruq3OhpKiXUfTis49neVS1AY7d0otymps4wSL3iyY30KmRsy6Ueef/fOVT3H/rGOgkIVHYjuuZeIOx2zp0U4icN4cs391Al/USU9qVv+kIYZr6VMO3/Y/zwPEKh3DuJ7w6OQKH0dHgV9IZjaO8jS6MvSxFS9DQxwPiI5gwrJsTqY3AKo057yrAqzr+2baKBXCsXvT/AKqlAz7NW0As/IHf+qMBoOJLgSZ9+QdeGJnl4ojvEqWr9aBb+bHma/50fcS68rmhXRAhofsAtiy/EoJcJWh0d5yvHFSW5V/WEVbNamHp6Ct/oXfTubpOA7GRfOUEPHhbkGAR7aF44eX43jskQhxCJDbAB8I8vKJ8YeVH2BpF8GdRrwS0tiCXUe5ySYKko/4lPvPgStVUBeX7Dw1Q2BwZcO5wqvkljbeVrMUqBs+2yu72Ezzf9Xva9PROs18XaSWMVvHd2YKtWXVocWZna7F3dPWmVJeUM7jQvdCKCL7j0JeFEBbUS/t8I0UiYq/MQgrpOOCm8FDrZv40T0tfUolzNI+oW0NkHCuchCv0L5+0HNv/npUNNHr0Umd3Rl/2ObtFYyva0C9EFfKqCP3G/tPi3AfPAYAmm/g3LfDpGhyq6B7a+Ov2NYzA56CHqqtuoFbosLIK6mziYAzFg1gHVn31ZgzZWMxdBY30aAqYPUUEKqM/BOx22RmtxbR+BlgIWmjKp2TdnWszRoE/KqYR9WToa6gT/RZaJ/33ojf2//QNWOwyBrLNDIrvg8ESHgtTkAffxFyvW+YIZPFKqUJfha9Ap3gOhx/iT39p9/nT+Q/ZfPvz54sb/7/GVuc3v7u/vPB7t7g929m93dI/z//4nmLLlFezUe2fUK3xLVUkmE0svopL1EZ13mGBelVYXwWMwfaJAaAwy0EbTnNB9MJQ94IAnu9YE+CyCR9wizp7CUfG/ujcIoBEIyZGeeP5WdSLwBwUKRRLl0Y90bpaxLPBnZYZ9dnFwxk6pKZDmRwZfmDd/FCRRLnXA2gT+xMfeg0rWwKm3r8bzYi5ZCIvzpypRVxqMf5HY124qsB/ZohL0NYZZATPdr0ucgFPPIW26QTiNS6LdoIG7heDyQtmSKysQqooUbQ4h4cP2qO22oz1IeRN5nPhvxACQGMWRvod4OgjbQuAM0fROFQ59hGAf8w9tWJUtKG5V7PtgRzqXFqETyzuETGKk955NLDOWXFgOUMlYoBSiEi+WTVid+/OM1o7b2pHGeaisv06SQgdyyjM7N1ILr1d0BWcBk5Pykm3au+KRahi6d6WEp+k+VlZVUXtI3JxxiVUf6G3hdGpWiBQ+Wl0Z/QxFVgLpnHd3HR5YZcuze4vH7b3+7vPv7yw//+Ob17O3B/P86uf19yB/YcepPwWBU9jMrYYB8sYBumuf4LMUeiIQret4rUJgelBUe4KQGnj/jA+QDg8pZ5klJp68H9K3o5WiBuflGQjHPlS66el69hRhwT2SDvZ5bGtk7vNnbPTqQ0kj7KDmj2FoBc/c5CbxWkoEURvnVJoWaCg39wtLmChr6U7gwcEdWrEZ6avFLrasqYctEvVQ9gq4cVkPdWH9Wbm8c9RlUV0/nieC58Vd9XJ31rDNsXZbMgLnGGRRIT7kMlJ2Gczbz5vMwViWK8Ai5BFzOvxxgV3DkQxsbmu6AXqWEne3MIeWciwzSKleaF3CvOVrz0IZTx3Ea5tm+YJ0+dW3aAGNiloGgLQMg6L3J6Pk/8FS9MBaX358f4b6xjzjT788vj4+xJkkUIlwlnP1dGE9y0WJ/9Kzv1fSn4dzzTuSXmbISSQir8xYS6rEA06U1W7SI0n8SphVeTYpWxGuZRGDboYdKl4Ksox61Vyj/kgLl48wm6VwpnrY08qYd39c7zgsCQFHqsOM5gHdAPcYd/Ghwvwc/Z6DCxbIyzvUBIy4upNBnmDnctodpCKibOFAoYTe9jI0SRJyaAGG3LiVikGNlDyn0CxYlPmDW4p0IhezJGwM6r2bn//1f/w96BhxzPsCZsnGUPFBiA9SbYaCppUN2PokTvfHl14jXf8jeJhk/Yu/12qPIm3mDmM+SLE3igdyKaLA3Gtzvv8fgQBbwecpJr/Si0CN97X1p+95DWSG4hlJEvT79BwOX1oOXytKJWYivcrn976jAouREupyGdoeluromqPiIbo0MmQH4JC/cgbjBgT74wcFAzDxE8636HSGDQJZIluh6wP8zOBgelv4WeQ+DfVQMpzzlajrPh7u9fm+CuRg7Ew6IoFb/2L64APtvtVuej/tx9WPeTPnXSjOwMkVo8+/OH2HgKl/rskxA1KG8szHJoy6f25U0l8pisTywWzNvlCywcghFoPrUYd8y+lZYeP3pIr6j3wFHd7KsMPpWWJX7Sne0JtPP2UTksLLErTOEsMK8UGU6zi1881ZkWxYKAyW55+VqLbPacupKwIifjwV5RcvEYxslnPaIRoND0XxasCysptTDV3cz8Q++bMPg//HmGjUBEvb8dKl3Gt/ctXxvzfKOBi4tvdX8Yy5r9QhY3TzTE9UvfaCzDpUd8lmfPRuHH3jwDPOcwFQYeTZOZ7NjQH4zR29ucsdjA1yIqxJmX8LfeYuuZbg/eghwh0H6ww4Q5BSHwFD2MD7p0O0bgp+WPSn/g+ru47+MowX7ksJZp4k5n2p72f5Yu2ALjOZxvT+6CMjKfb/2IByCwttamYgeyQ2EvDdv7K81CuEPAz2ZavuPtO6YpraRRw8/wL/2Kmw6hnj2vDQ+8h7E0d1MHOkmR3v7B88PX3z98pujO77cUf8awH8U/gdb7e6hNFgkp4ru9RQB61lE63A3R2gO9/aLRGIPcxjXdKblH9Dzwxf7B/l30GGnI09kqGuAUFJhDGvhvstd8pVtavQsz091BeW1EUs3YDKTspCuJ2g0Z8pkrAlvCZtCWpyOJSOw5exN9XVijGqRIwHOUC7LuVmMq3XpEDKwVm1alkmDqyuYttCqPjAEyIn1FIbsBLRijDc3f6U8CG88hpfBxgtwOxqhcDGHgBswverSrga+mFRa2MEw1akqaCXbiZN4QPYyDOytiuLtqj04o3Wf1Dn5RDJ/g9Ptiw7wV9QBNimh4rTla5aP+IvQ+kVotYTWd5KWthFeVVv7r18E0zUFUxk5u0nJ9OlESQNiEieqZkeWqAtpAZpQpQ+srbF+iZzPXNxsjSf1gxLE9Zb1aoOs13QRr+IOfssfXK7gdUUX6Nb2+OZ61w5J6IMSd2fJPR+uzhmhYi75RDWPtBhjUczt1TsB61f2JrnnRZdgEI7HXIrFyWJO+W2uJVKGf0jFbM0HwxJBLxBvukhvycpdpi4NLg9XkpFLQ5FZRu7IS4Ce8WIeZ9FSJvUI7QxFDzzU+suEAui3dRYtTfQlGxd96WUn/wR8riVJAR5CqDOv9AjmY+0XgCdZxEES8yF7BdGSWPWCfNd9dJph0L1Yxv7f0H9cQB+AQ/htwRecZo/wxuTbBQ8dHEMcVCVDddVfZNJTTn9hWyCBq6FxJgELxzTj7Q2C9NCYjscD6W2V6OiFAAMqt/VMLuQZXOhnavK3NPlnPX2xgh9UPkV3zauuhDF1I05lDllZXtQKTH0bFD9fpdz9+8fi49NbKMm9wu1XuWzlZXc2GhZXtgeiRXEpz/ehXq89eSMkyFnv7+6XL+Fp4ZZt4R1D5zoFGltP51PfPCzItYgyFyn+2O89JOkdOPvbaHI/yrZQ7hwLCBN0G0aLmJc3T5NJKiUHLrJwBgS2WlWqQ7JqVUpUGeM+Q6HoyWUgyYYsBBG8md2xQ2x5QEYKECMsjn4+pmAidHfjTKaeYDMvXjL5BPsOrmA4An4ocUXC2YwHoZdxSB2vMwjmQwx2CPWhETikMvdMpjdsGjlEMu+aXLHPAChkc0mVn5VCUHN/qhFMalJmqq/IKhAm1FsUjrm/9COuYEs0mLh8OgrcAQQ0Wfk4TsBc6suApiwpBLuoN1ebxLIaAsoPlTvQDQHlR9mDSmNGrC4dYpxylPN9gKONIWQ0zi/skYg8pq5asIg5ov8nuvF/KniXknihUujjYJ6EcYbFaLOpB5lnUQRQeDzUDJnSzmVqe0gmkZUQK9z7KRP0oS/JV2GcIbuAR4jaJk2GyrmM6bpoxH0BeCtavD531qntNh9JEM5PcTpuWlCeHdEVHd8t35BSyyR3agblqAyFJWgZikoFWgTBvMkiG+FrUKTCPqPa2MFyAnk1e2+HvtPoJVwDfqct8I4tCrQECLF8eqsBM9TQ6k44PX85Wg2n0xX74TFIdX/DyBIlR5+9yCbe8OlQhqrcIw8uTjAm886m6b0a003xTXR/jkRsiLarse870PhLT0CAEwO4laVEDjbmT6DrRJkoIbUai6nS0gs4M/b1kVHzcD3CmPQ4PAMNt7cCB7ni88jzOfnKHUzExTtaIkPVwlfqPdJRGHli3ZZDrWLwXQVWqgvXsCypTw8rtWk18l+ZUD+CdFSJbOW6tAbaal1Qq5rrCyDcogLUqo+vEoEb+so+lC6r4K1ymkAFyNUar+IpQK7+skaYv7CcU4OwVZ06qGUMTAZIw8ACLcjkhVGCRYd+teSAvdG/VCqkelnQ/TrwX5WDm09U/MKMpxPMzQJ0fRprSKFAK+l/6MlMvcnOH2prPrYlZRgxrLYnjLXzupzz4MULRIrP0nAyyYWCqQRHW4+jHinVUvY+WyBKGRgXgVTJ7ExwDmFuLbkr0UezLR2w/IMMV8c06BCqKNmZ0KIvIfRns0WMv0v4ersIPE4quIfE3aCUYg3m/tBVXRDXhPtFfhlrW5oJYnlnrAU+Sjxptd+rSthrmlqnZ3Z+quKbQwpAl0de61qr7kTHf7T1FV9jOzp8vfmWvgv9OLHcCi5num4o0uucxjJZw5T8Wz9ZxLZ0bXnr7Dta105d3JrOKJeILr/j9+pgRfWRekPEknOvp1N/uS/znVrvr1OX9rtVdU/K5e0XqoKQvo7mTukboo7Y2qziYvPz/KXGbUovXte7UGSqm6hSJ7cnZoBPK7FbW7rBMTSvXUFW15wsjMPW4vg5HKoXQaCvfv3gtRdzzy+Hs1qtPUf7HBczQV2VLERJ3yG/96KBt5gA1+EBm/DYRA/ZSBjI2XzpAgNyF3O44VBBJYzHqSeydOFj0BjCZCiUNzcoG85hACV2ZK0TIOkAD5e3YJfZm9oD3M/VuJvZMtPd0zM4xWJuKyJ7aqI+6qIq6qJxzHjFgBsdp2PtSM8aqNPm1ZCobz07LlYnW+VKx1dQq3cxoMImKY5XLoC3utrU7x26Fb6Mp+QKScFcyNM0SdlAleDLEmsDXM/3KWgjCKmL+pStNUiZlj5aojwYCcYWQormQYnzoBtvUY7VlSZFx5oUfadJ0bbVpyR0efe4JE+yUo0wpaoQOQK2o0j/NLnqu8CKpIhuYCmlhE9eyyJtLUBa4qfH54N58sDtlBBNAqtxIr6Tm38txYIOZM3aoccGH+4g2RXBZMvyHYm/ubSZruJecZC80KdS8fWs15D95FWxRUD98pCWmHV06Vbes2L6EKTGXqqfan0u1VkwNyrzhQrfC+udmttdr7QoyByrPe7gXMV0Im3slYolnshA7dIrKjEqc6Eou6NwAQ4O9/cKZ/bym9xe7x2+KG2XO3PDYnZmCa1Z1g9rsKxu8vYntvStx1qs6l8WZyGNZCVjD+Jh2RYaRyFGNO8IqfeA/KoiYB0GHpSQiQJh6ci+knu5ROyQJhqKEbOhYl+hA0PFgyA6KbkWty5PX/XZ6cXJP/vs8vLmn31288+bPru6edVn/3zzmkpl99kbL70Lkoe4z06uf9i5uf6hz/5+ffF25z+O37zeubmAJnDRQZenypZUSR3yxfrsP88voSB3ECZ9BunpyXbffl1Tbz4H8BEMDZ2mSZwsRLQcwmfMIxRCgcWHF/HcQ/SwFDAXRHjPoyVbzGFXDlnE73kkNwCBRyxSDcvVakAA9novRuPJHCpZxvkzwh60tew+9EhtAJoVsXk451GoUhIWsdlTuZ3hjOqP88wfbveV/xOHB9wqGt1YgawQU1QkkO9DtVaurSNDh+0PjXsjrqyDyMzhbWE/MOXLi+sbJm/xURgY8ehIXWOXmjJRrokLE2jVxMnPyxcXSx0+GhtfxVCWO98RlyC3kuQ2Rp3X5wfVRqGr4HML/Nd6fCiWibtwbj2H4QpcjZJ4q1mZIS7U8ZA9o0+eFWdUcQfZVpxIErMjkxbUa9oe1ip3xSl9v5h58QAoLQqjUj5Vn+fzwUBHbraxHkcP3lKC/bGBeSwbeCMl+5hlwrGujGUYUwspreOXvOhgLjH8p1Fp7YvYexjfBnz8/PCFzf5zB29UXZ2MnjtreIZDdpM/TAMwJ6mlBpC0rCihSZwYlldjZ6F1RPttNOxVAft+sfGtZOOb8RlkIHVOP6DvQHVIycBboRID8RiMiC/nv1HYAmHcIvXgDU2zfTRhaX6b0xLTsFUEV7ect8zpmv2Ym3fZnFZZDT3Pk7Am+6RjYTxJwG9Hy1YDqObuoujuUsMyurPDN0hSIPO9eaPrfD1Tzwk3AX17H25rfu4849JOfTRZYp9V8tenjr1oQFTqmvtivf8yrsUxaBSBLBpTQaGWFrpzbX5KB9J0IjWMwuQ2SJqcuDRfCNBGCVAHuWYEUT1f3vonSv3B30xfpewf95U3StTYo+fjpVTPXogFmSK9AJR8+E9VhgmHSQGQO5SorirbAMnXKm9ohTfTDetayn47fyDhWDkppZbSXnGZ/5Ajs+UPqYqWyvaQ29WX1iJMU4H51OaedKDDKpA9N/U/55umshTp8jNQbuQ12tQQb+zr8chUoyg5fhKO1/R6V4rib3idmGHgVctA6MaqlIKsGP4Ory93sJsK3P/yoFZ6UB1ZBbmC23o4JH6jfRGrMB4ruQPVSxEhWMYYmIoHaHucAZuCX4D7Kn6B5io3n6CJd72pcnIpF7JS7oYIjOrwixHhU8rwf06G/68mxBMITEl2pz9XPYKOt7T7vcZ0R4eJCPEfoRxB72gPjUnyvwG4SUPT7O12ltQXURaCHrLjjZK0dSzmMTRm+mOJd1c2h2Azr9RQV5qFckX0J8zQSDPBtiB/abtMaHF+RGdVb+/UqC1Eg9IMRknZV1gJsVT82jj5yUOsHAcGp/LzTPrO+SM/lRzyRO/bconQqZ0H5dfe3qlb8IgwT4jEDylNG1RMcPeWHsRHa+zGEUq37PxUIkKpUmMwhvztwRN2TGnXclTWw4f/GSzSSLR9/BC9OE855CbyAFLSKciw9MjxPZdW+Z2KHHF0EcZBeB8GC6jn5+ytkjqoiEC9h5dAH2BR3agD/g/OR0W4PFY4gdrx1eQ0mCcFxDl4Bdw6F+pAk3xSuoBKUMnjXWiKhLKy8rbJT2y46y/073Ojf2RzFH9lOqiWWH5adW9exsTEHOQQTZjkGEAP6p6mvevWwwQ0iN85oW6XNrz2AeeFvfy892QeyCxPsyiclyAo1KCtpcjDgxcvv979Zm9/twTGC33nwPXZ1iyM2eGbbxn/4PM5gLNB3D9Mos9m3gd2+N2320Ob1rRlSQoup3PIgPqwMlbABn2ygwOqKyTqIHRT3LAYzOSMeZcVEqvjDS70XNsAUVioviZKvbjojVALk2xnd7xweTda53pCVKwj39M657bMr1SHEcw6shajXP4N+WT0KV2r0Kg1izLKIj8qdzpXqEXPorGXizSchJQaTp+oXdHaj7pxllWlXVb9m/M3ZzKXfpxLiq4iBrEiT/l+XkE0XqmOBrK9zrGJOil+nEQBTxn0ghLeNOQpmL6WSGV5ek9RX2gNlhG8YinwGnwsH2bjXlyWMlAcezL3JvykEMNRsSdWzgGE1yrEOLs3sBq+5vEkt00V3VHmBUSBQIAwmBcXcYaJEjpmGLrrqZownWeJJkyKl9RRx6Zgjqwj39Ng1p37VzGYRjjOZS9KK253w0c5gFRkkOLvTYRTwLAPoH1tFtmrLhXe1PO65VpO8+UA8vVa7LuddhulIS4YJCTDrCwGNeITSqXUv56ogPCV12i9OBldXqpMo0f7cY1o59NFioG7D66oZ8DjJ/RBBB0XdjSqBKvJTeQMM3A6z+GVF0aQsZtyT0DceX6jJcHBMt4y7RGxEGVsWTFqrJZEmOQsF1ZlKSFIc+RipqpmtT9J6HgI+v2w/P3rl9/YTNTUxrmFLKDb+/3hPBgXeOtRTrqg3y32sv/85eHXL3YdRDuX/GQR373DPPXc23+u697IJvsvC6QK/qCkQjXnHqLTP8fCQHFAqVU2UaCymKBS+jPOTpJ0DnIw3IsU2OeAEp9293oV1W4KCVHux1NsvX+0d/ifqOvJg997lHqKVUHLKzoKPjW0UuesqhoFvIsXUr6TQrJVp3rtUkBERgIZS0pzrNRKhGFEhRzdwMTU5yqfKK5LSGOzeZICnIA9GCHx2H9h/MM8TOGTMUgce2yaLFLJtf1FGmZLhcKjMCa9SKgiQsLkEZFgOGZhBip3/AxNgPchpkwBIqy/iODhVFvmOqT2SGgOw6fBW5Df0s1VdDeKT6VOocYGKE+gu7ih5/FjaBsXJuK+A6iO5eNfRydZXfVotjt8NroGpR2bA22hUyhz0PVB/hp+tC9D86L1azTV+2D5gvtJHGxK39mCAGRMsTGCX98k/vWlaLJdpQi1yL5GTWjLrvMptis1oar+qGEH3ad5Yg7lp1rVaZG8rtOTSlrPJoRJ/AwQkbwwEkVZEg5p9cKTmyw5+c6humSpF1ObW5qME5Wl8d1qE7Lk6CY71QzAtqBy1b0XYkfb7nqUuUy2oiysM9lc0q4343EAN3gFeXcXBd4CMelNs2wujnZ2xMHQm3m/J7H3IIZ+MtuhomM7d3z5f/45OJ79PjiOJkkaZtPZ345/vH4++P7N8cng+vvj/cMX/3M4HOYYzdHBi931JOvD3YJkfbBfeBnwh+KdhgPM30H9WCG3T51r5MWTBaUD8rilFO2+Q3iU1k+gp3QofWSl5H1OdZD+yomC5hUX8ag2X8u8gvLJNp5mR8+EFmn6KA5gnLe6xgi5K6FGAQubilICYgAeVDrxYhBMsimfEXTnfZhmCy1fCJKxUcoIbXeC7h9/QjwEL8ZighLRe7QIo0BJKUo4CcmquASp3KI3tQHp3UXpT1/n/CkFWxWFb8u1q8mWr1qLlJ9Sbl5fbOwmarwCSAGtnRkQ0CcsQd2Z5QdUFDFM4oGYhdkUrT6S69Pd6O2cqqSbnVPdWqwoFdTzaqd56hrmxf4nO1ZmaVHY1H+94soXJbYJDb+pbBjqerfRsoi3oUiyKvFK+/oXZMSfogZ0e+L8VmbG5mpBa4vXljceo707CMU88pZUMto2AIntxybnbIsPJ8M+e+YmCM+282WlIa8Da5DQJAplptdS4KAvBBEns6Iu1mEUvAJt3AjBe4xsoYo1u2s9G1RvhfNNnZjwDAjosLx3utizQqMqFn2GPhLb3NVc+7kuJ6m7AOYq1PxEuKlyaDnnjQhzsnBwXtda0/DYRQy6BgkoGetdJaQrSyJqrNXc7OLW+WNNVZtL+1sWUBymh2FJdNjb3X++u+uozrz/sjZo83PXgR+Rh5sz+gvy8HIN43GS+rx7DeNS+jnMShLyPHeE8BsaFtxR2cK/M7QY4yNR4YUilGHMnhkD8zPydFuaNVjtzLeTJFPdLZBHGkun5LUXJ1co8ieLDIIH13Ld7RAX6ODBGy90gKBkITVeO2xsjNbYnmzP5MYzlzVfI0PvDXniJPgtGn49qB0d+8jL0K3GH2Cr4ZbzOFlMyJywTBYUoEqFuzw1WRocC2D86vmw39IIjl6+RYr1pSlAI8amYgGou4JlICkBZuCHaTgKoRCvgDLVKpZ/IKNLEeqrBoWXbu2J2reV4xpxYwvbCUuVEizgL3rxhG/K+2fMjhbWtzSSwjoyiMS4lf+sCJiuMHyX3dhJyfzR+lO7rru52bWxza/MTqr4kerNbBd0CQiQPbIqS1vzLeK8qX/wWILTBfT3W/UF/onHgfxD2SuKf27m0Hi/CInSNjUWQ/Ga9xQ3J3fBcKeUQ0wuyzWhBuUiTBFwbgKejHsE/hstTf99oIn468ybz5EICuPZ0KPDPnYfGy0nawxdOrdVlw90HDqTB1U5m/Lo5oqsuPyVhqY1z1oJnRSeiripxjylL9EY1y8nYIYcMvAfA1FO4mhJiVLQg8pJN84OAsGE4LKIusnCmcLlhM3ZxCQxNu5R5ogCao5kNk+2GOsm2ZY0qas5K/viRxeS5W2FNdCu26DNgWpiP2mqs7evqEbvTDLBY2KDsqI1CLiiD6JuqKcqI/9nHqwrBkx7RsEyMGOEAAbc7WGeTB4d2g/80PXkDg+fPy8/hhe7h4cgA6oZH+gZA3MYJ1GUPMCTTpMHYYqTkohAK8oocJIOztQbpTnDSpQgHycZ8fnKeb9wzfvF7uELx7wPD/bteT/X836VJBkOxZJYlkb5oKhX5KXheMkepqE/VdvPoC4ACzgAPZM8CM+aj5OU09UcQ5XX/KxfNM/68ODAMeuXL/dA+szf5Of7rSHPlSUVuWtfB+cZ7aRfcAcacXHJqwsltqnn4VDfXiXpKAwCHrOBassiz78TThXOmhkWzWtS6XRCndbtcHEKshftLwVW80RY7FoZhgfhhVjZ1pYWho+pxaF7UJ+qyZR7mCaC2wKurCg84kYIzk1MCVgd9T2b3EpggF0r8WvXOWFiX74lZKEdE7Lu2NYu5ZxtD9kp9Yjug91hHlMmWGeqDdNDxlUxOzQLCswLZudjlszCDCOdkJnBqb/HjXyvvhc6m3DIruCZUg4/Ii+Qp3ZvV/KitVVRZbVuqYyeqvCyWqupaiUkwFIOTAkEnpQHIULGkTnag5uWZgPInbbTG68PKGb0neDjBYGEy4uotEWsy9hnxpYMNlZPaIR94B4JVhqM+MSLTECY5RdH13YVzpNcSVerKvpB1cetzaqJn/FsILKUezOnnlh2Vo7CGE4Gqf+UewEn/NYTGmCg3L0NGVmwW7Whyn3dowmgc5s8DbC/Mne26/c0FOoMHVa+LPP8KUoFtEiSFqyA2OohYJCD3f1yp1fyEtbdwEJUr7XDrxM6tHK/lzZuAF5aOY6ktPrJ1ZnC9AEv0rB9PZPZSrbWR+bdbWL23+pofVVHzMxcm3bRvbS56H1tMK29oF25cOvoo0fLDNhJ/HQAcmMXC6NWTkfKGDdKPtTAmwtsPcDiIvix/R2zkgaMoHF5+srIN+wM9BCp6ckqXyGwbazeQkVF8D7m+vWTJA3CGBWDrd3BHkmx2xA/HI8hBQPSM/1ElSOfRMlIKYLIlS0jp3JfTsPJNAon08ykN6DskxLjxQwHmDnYPHnKKLedinpgp6gAUHpoDjOtyRx54ac/4hmtYZDUh4a+1k9QSKRkOewSsV3UrqszWKHhj+pCd+wVH0KxPJkr47bZannJ0wFqgXrPiQ2VnkxrjJRcYZCqFV3CkHJBW3sDWdt4Wxmm1gBpaWePhEMmW4oMfx+Nkg8tBjWID7MwPqcfnyOog/lHgZnZb/2nD7t9ttztsw97fbbc+8UmCiDcq9cvg9vk8y+P3xjmfXJVIh9IXPQOn7e0AH9XJDfM89NEkKkG0sNSO5BE6SwG/3TdUPgfFfQILImup5crkuy0UJVrrViP+DD/+ihMW76Wn9QN3tMX8ac/LNtPT92Un3aHe/v93eHXe/3d4d4h/NfhL/lD2x1+8zK32bvAeWVfD2EWU/Fl098L1d/+y4r+vsn1t/fxF8x1bAr87ixqGVHk87WbrG4nyXEYYyeBskfxwGbo209uOnlsC4nN1/RAc6phtKIVoezRDiNwtZICosSPuZve520HZCEQGGg0J/enNU04suv1jDM1cyWWijYLjHXKpEsdSV7O2uFW3On7Qk4pGfqLizhbx2jTuATKRNvwAtaT3bUk0lJul7eUPqsW1tGz6j1IT/y4MgqAiXkUookGeqRMAvkLlg3D6BqrSp8Ok5DmbpLhZF6BEVT/+7/+H27X5ekrQXstT1FofqUKCKJM7mH9pDgUU4C+SMNM2UfnSgQTYcB9LwWgfDZOuZhixUNpbcFhpPXt+e6uAc+QcTvsfSH6+T1bxFkY2VgUapGyRqQ9c3p5uelgeAj/kFHjeeSBGIsuXMzb2MpAq5kFfbsKJGgtizQDnwdAfaa2G2sbu8ceIKQFD4UAoVPQVQZeRBYGGHwgaQWWUUxlqt5cOsy2ZOCo2kAdZKgFEfoaszBN/KL001DVVhaFd5z9kESLGWf7uYePi98/eL4NeZtRhLKb59/BIYLAMhhDOMjWzz+Pt2mqo5R7dwZgRlroEKErWsJrCuNJRNcIXKExD9F4B/YUL4KtkOtSihxnicquVUZU6PA9j4P3VIneZtAwKw6QgNaz1a+dBkWRcsgu8R7jvYkTOgcwwUry26TbXcrXuLJiV3jVGwknUZ3p2FwH5FsnLUjdedSRhS+JKf6UpAHKxy0R6ZCnorDnnNN6OlI7JUcvhry6cNOw7qIuu1UVI90iYsc2UxLkuHT+EfIG9EHm/ls6gS6xPLXROrVBr7UA6CoSL/FhrzM6mZK2kdITxCOn5GaMmU+T2ZC9T/z0vSH6WzlSKan39pC9zz5k1AyJ5sAimkT1INm4QEkM+RjqsJSqmmftjA4yet3O83YZIgrn1D0pXaNEUogdPOalosxIeWDpmYRJXDHM58yfJpKvYhc2GcQ4Gwu6ZbVgHmsEKCZW2X8pMNmhOEoV7/L18fnbm/NXr/77v/6/a/bm4ub84i17dXHFrt+9eXN89R/s7+9Ov3tz9vYGMo9BRqQOTHTE9c3xzRk0YBev2Lu3p+fXl+9uzk7Zq+OTm2v8qAC6s0J4hhUlPUtgL27HSXor5bHbXxfBxMrUVm9LPiH7kkL2c/Eq7esD35PHsl8XVF3j069SQ/+sKmhJxvqihq7reHcoRjo00OW37rMqNRQnIkiDUj56MpGiyA0S8cZ88KVZm6DCbpM2EnyKscs68Kw08zV1OeUIHEi063bg5S74ceSQ8ipoybMbdrl0Ql4fWB2wre/Obvrs8t1Nn52evT67Oeuz78+OT7eB7eZgXGU+kgfRXIKgmXgfA/gGKi7BgF4T/1Yls+dp8kFyObPfx5fnQ3YmQJYPPVKwIw8SyYI8JqHQEQroGiAvvsLYczpZaAekIK62gZCRmuXxvO/2sSHWV3K05BFeO2Hdyiy1TUHEopRy8A/urHBT0HMO1PQlS9Gn1nLtOg9OZaXP7aNt1Uf5QZknYZjUZgGTZG+ro9uUR7BgK0WWLnyiBI3Zm+8E6tTWN1TjnKSzxgR7Z504N5hAQ64cOJAQasb5ZconzkvRsXJRwSqvL9sjwBWuGvLwaaFXWkAXPrJgUzm6iqd+stzwWlqkNOHvzm56/d7lO/hfYpW9fg94JWnGMo5RNiuv1ma7wCIVa1G0qJn06ABEwDDVyPgvdp+/zJVYIiSmLnSKbe2xWRgvMpSjvmaBt6Qc9k6QITKOi8LKUO1/d5OTNJShDqL1TIwmHckzoSvZwffbzfm2HcsElHFJ7AnJqgCUj0YWSJi9lEC2h+xHMqmSYutYXZ/xGJMfhcx7M5CUHvIXjJMZdi6C4xAqSVIMf+c7f/yajLoBgZ54gr/x0jv2azJSwCplETJTtgMJT+6Z72R3BuT412TUZAy9pm80AGWzEPZ3PTvLJPo4EhhuYYvL7Qk+DPg9bhxFuohKKBtFMSTQIY0p3Qo4cwOzQliHZdvaifRTWOdEsQi46+0e5I2M79RnRanK/AP3FxIikGwUF62lUAOFJ90YeeOY0Ge+CoC26Zx6skIlwrHxOW2bsV7ViK5NuWD5IgfNI/J1QBRnHFNUsVsL3nJj8R5wTSDUwwKV9FcATm8B265GM5fYiGWff2QpzPzPHE0qk+eMSajdWETkugyUYxQN46xnI1HemW7ubpnlW+ftLmTBk3tCyhgyHaEqEf7K8vD6Caa9x57uhD5W+cuiD/B5KkZAExDKkQfvphctRUhJVfwDOHobneq5ggiUREa+lbiQiVPPd29oj9b1Qcqt3ogLUvZV7YHskCBdPpj86eoDatJsuznwsE/tuIsoGeIzSb7fQLWfXHURa6ldXF02zHEOOwtYFDn1ALYShojaojFXFqahPNIiQLMO77jVz6p9leRKxqcX4ggTcbm7ir6tZ7WerZ/jn+ObC3bz/Rn7/uLtxdXxt6/P2MnFu6ubI/jpEtyjWTgeg7Ay535G7xVwvGRgyglGkxCmBonpyiUF1lx8EJEXzsRwOIQOf7LwvFQqlXlIkKQLLX/pPa3bLHfpwFEWaYjgl8+/rj7Z6mjOL+GcxpdmP81Pl/T6hC6zDsKJrA3V0k1zTcketCSdVVi2e1MzGQdeaC0juqhQYgSgCNk0QT+HCsOaLkdpqODj2L9J2DiaaZ99B/+6Ov5O5bmov4NBLVvKMozqjxhnBU4uEc5CyGIHQED8zQg8KY/4vRfbU0Q8K4LlAYhhLxYP8DZ0Ggwqg7RImn5ZLKGff5BJTy3kkVwejcIFaDmzzZkGaDktXBv26hFLGW5lRZX2SkYs95A++2i2qbmL4/OB8VPRLpjjyeckUVEEui07dEvUpds29oA1EkpWCUKqSxlqKtrQVIthBSV7vepjMpGjHQrSlbrUNlnG626/UchHoduO7ulI5p12yDNqJ1VfSlwvVezAwABsLeZgqj3c3bVCr/DCdJBza21HxPXbIi1hSkd+ng7AJTvDZk3kJIgwsaPyH3ToG40+4pMQTNx2wMFbUFLGyHbzISqC2YVJZAi1AQyheIbU8+8w0twTzAsCwl1YB4CpaQmcHAGPvIANwDhdq+hjK81Kn7QK2tNpKwCVQ7HC+K6+O7thkucfhYG2RxwpKcSkzsqQEirPm0/wk8i8Mm1UISCtjRF1RkN8Zsv6gj+1sTkGoci8ihTFgi2R5D2LC6hv2VaUAIMPBZvBY5NNiHsDp2juXHIdk+oY8HnKEdsRbVlmLLgPKIBeQ0NLQmghFNE2W87d0jCad2xLrtne8GHxEpRvlAWv1ylGwA2XoCWw9rC0K9Ug7PcOa4RfpfCR2+EpFLR3tcEAQDdU8dxH9Mvbtjg6iJJpraVgfW3J0/JYhfK9j8M4cGgU0lBYIfQrrx7pYr1+D3UxwATBJwJ/QLkarIKJj/8X1C38EgTtfJiA/qhGlzhiz6jLZ0hxwN6R8imPMVlFrUf02TMagFrpvBb8YwgYOM9gHvTrb4vQvytrgH32jCakRxqFGKU+n6eJJwsmJ/N/VNBXuai93Qq3/F45IuEN/WYF4isVRYdyDtn3pP1KHUYs5mA+F2yPhNF/l8A+SmueeUvVhpHAureLCFA9iqlvESNF+YE4h9hL0+ShqD/BKygWwRQVYX2SkiUxvxhTZnThATYqWbaLpSqRsTSdLbEN6XvaBjJkx77PgTPp7CoidDgq7Pz5KeRRfOz3PG0QvLTWA0+6Pm7hKOVe4DCoTL20dS7j61CoQqXyu1K0L7RAKybYUgZJOpEtZSImITixCwWqJX06DzGYi70YZSb5RdlGAT/itK7V4M12CpxQMjbz3RRYvt63jSrhtWlCGcTeZrdJOqlqYQ7e+bOMXepiZc+Lw0ZVb9+HqT7T4Rs7knAN4Pm3iSp826bC2qeqq9ZQ4ayFofMED0WDt+HlLAcNpcBJvZgosixRRsFmQBsGKDab+HB0VzS9V7oN6sWy8wAKCsP7OmIpH8CfJXocyoHow0onubrAuhwJ9lF+9DSCefbtrJPQUkVaAB11li5rKYN2kzObbyGZ+bPifn6+l/MpBMk8bSv7nOtJn9PBYF9wKoYwoRegrngTxTTyJPFOWzbEvziybmVnFEvItvBN/Yytf+5hljgJPwD5r8pTbG+ENJeM1irl2hWZrlVpohRdIx7pue/8gf9XRje2K+dzxe+TuyZCJRsZEcIQpWYJIqWPq2QIq/5OV3JCPbtoyJNxKNAdcC6fvgSoPPtNDUFbTM+UNrqTX5CigNv6BR0ZWNSBTjqhM5GImxXpW54jWYW6AXZG6VWUvAJXVd/dZwJijQHZFME7jjHJ2HyXJez6QGLlpQSCJucm4x/vQ49dXlwbY6LMLpJ7YBkUVR8a5TqcTHi+ckp1bhbuG9VtbpuX9c7s4eeTlFU2mSjap5FI7NqTKxR0L5+9RmutyBeoMPo1Zyqtkshl2XajRyliWkhX9xZZUrKvq0pijrAdlEY1IO0D1AUacQa9zLws9BFzRDo8yIgMc0TvEky72xCS6ygjRSh7GbJXkNZKthl6mCQNY3sCMGhK5Grnl84DAOf7+NjvAaC9y7YAP/EP2a3I+Lz70b0F/yAwIh4H8ySM0VAIG0uQDibuvQZ7zp/t7R94I5+ihax3omuV414NKGtsWCpcrtwdVj87dhWzUjnziurl8gX0mvrr5S8ibUvx7tBfiyerzk7mEVUCNpdquOoDVJQQQavxWksNSO+bjCqBBBUpXec5gUE26tNJdaP4yER9dG3owPk+/Hdc0xsxBdMbTpp4hnVJ8DFYl7Fn90Xmi69ffqM6s6/NSlZ/JVCogrNWmVk7qtIpgx0vYMWZPCIZ1N8h4OvYdgZsIMq92d/whLIcFXjFu6aJL6hET6Tv2dG6VgZbSfHrUBLWipBVb06KhStX1s71J4vMFV59n4Uzb8J3fp3zyXZTGHPhfrlrteqSpAYSTbHuRt4q1dOK1BDig0mBucq3jdErsiyCWjIyROlR+oyT/Vpn9lULPxXK87hVrd8hOybIBdwNlUwJZXchHBhg5mQ4jeyO+M0ilTUXxFKA0ZgQ3N7y7DTxRZ+dRGGCIaHXs+SOj7woGrIz4s1HVVWFdyDA9llnfV7yEbv4ITGStgrVieQ7RBNz+oorBxXbPsj76EklaZAlg+uDfBeoPPCAbHhEvyXGhRZl+AwQyckqQF8NTZaG0uTUL5IF8HsdnAiIktpoKSEk52Q2lHtAp+kwTNLPlp7USkk6sXqVTBqzDDekGFVCTehAsIofm1MlXTmRQJMisG4t5bpydXJ1/eCCXKknKf0dFJxeQDomSVO4Ct+Xh0RYmg4Cxgh4259LbvhUIARPUbL2BxvddMNWZ8u3G2Zw/2g0eXno5crsKkDRq5FZhG5lOGFJYKmuoq1fEizAhdSn1dQi9ds4832nTB/jEhdGHTvzJs1M8vqAnd14kyp7imHnYCHwoxBrylLVZSn24uekX2F8Ub/ujF55YbRAg227M8KonJMk4Oq/31CC70pHhvSl85mZKTQnr+P+DABzkeKJEH1Wd6LmvkI/Mq8Z9veX1mLBJE0W8xXCAuR3rrAAkWvC7kMRjoxm7Bmai3zb+G6G7Dv4YoDF5DTxFRTll3KfQ6SN7NREGIcpwWCBBRI+rIkm+E7NuZl5/2CvoAL24HGKpRsXSI5/9GrPs5Pz2Dqd8q3CJkL7bbAVwZ3RSekAPZKqNGbmxD46uQY00ySRqDpYSSOkaxlusBdDuLJ9fWr9xN/JNXQ6T+0tbuUitj/E1EyI9ZQmC2Oi2NhdkFvi2Aj69BvHp7mjkpoklAOH2UoBipzvAi/RUyj9KD2UyG879f77xcyLBzBtBJXEZSjOY1/domzRWtWz/pyPqqQdnC/SeSKafKVHgIPOHaR05w/8v9JZOvcyymKre5fvMGah9l2+k4EU5XfZRFPRf2rAcsi4hkETU8AnDfqypmuGsRn23kDcHWQdpFyltRrIdqtd+YVSDMYaL7RTEIf94flp4X3GQEbhAcqFY21Y24nxJK+2UtSXdMWI+Rt6425VQV7MzcryauOfECGspZmQP7DpxmhJvePlnbyw9inZT4RdekLQa0KLPTyo6vfUkvL0W4ZinGKrWvJynYyzAfVWpDHZ1ANFlEVJDP6BKWQQxRA+loE4pkQBQS5SabMx2GqhYKMowbSMB5W4T/2KLCTcCDCbCe2AqwnjWI2WUAcr0xJ9hf80tMJuTZuMZyZPSG70J6USrTnqlHsRWXFbKCffY2PmT7l/5wgOyPPIqdVYU4QfbIG7GtCFBmqZPE3GH7xInj9FCrK50OQKSx4YEaTW4EIiyqvRCghOffFL3oKnzXLJndVI2vNMsTR5YImf7oCvATKx2pqUr6Rmh5Xf5LeQD+Itpfm2HJGxGEWhr9oo+zCcIlWPQ/shUB/VnRiyH+CRShFKvgQ9GMUcUk5+kj54mJmHlRSW5DaTUa0LASByQMoUiNsDH02T5K58V3A7Lvz0RI5xBXNtZzZWs5JTaUu63pSUErlB1itvomH0AZZ3AacFtt9zjHWVb0exLCqNylHb9xUtRUY9FXdP2l1rSBIdUDVWuTMzlQ65NBjE3lA9HJgSMWF9EZIV8cLaTalg/DT+v8A4AGVSKc655WQMqnGn2ZxfX1hxolQC42Ea+lMZSgBHrKzoSL9g2rxlnWQ7wt8KJdQ3q9NMv39zfGLdNkWuS9e7FheNqFQS+nxnlCQCikuLbEeCFTlpVYLk0CZVZ9SaYQeUwoJ+vWrEEfkFUB1gPBOJRSNr++Z7KeKRgItKFQmjKJLXr99IOBGFsoTC5Y0O/YBG2KGEJ5t7iJHjCfYeM6JxyPeKoJlEWSCWOUIazkBJIlPOIvX8ZZnEyRl8C12C2a8VdfvWrNngRD1O5GAxP6dj3g7sl5O1ynN0ROcBljas7xbvZJ2HjR638uL3e5Do3ZNG2+YyQBqrQZVp0l/dhq0K0OZRvDshMhXCdFpBL7UCWpI+M3h06/jMRMFpVtBInXnRuSeny06VHpqDTm3Sl9sq30EH9UjFSQWhiuJKthYKjkDnPxZAQrpclJItTfEwhCQ2o2aJ2i+d8Uq0bQvKTvWtInwdioFdKSIYxvNFxdmwLQ9yMGMPtVJtPNcz27Zebtgqnc8BIJwKvAS2fQ1RBydedJvxdIbgbEFI6cZ+mKkWfOaFkVTY3cEnlEBqrcxM1drTGsMA8qp+L0fRexU8T4Vst2R6Ogy+yK/MYJWh8634nmehbeZZEuBZM81C8zeKBHQhBnvWRxSeLXiJ42HheIqvLowBfVQHx6/M3R47Lv6vy92sa/X4jC1JEVQX3VAGO3IjPK2SY90U73gXllX+OOVjnmKx9EfnWrk8Pnsit78mI3c6n6tVs2/boO8WX7ha9fkp28rS2+Fw+C9P2qutZGVivgEjmS2huY1k0OKLkQysQAl57rWRDM9LZCn3AIdoRxYiaz42ANvWnxVew498dA0W9gxMGy4Ybo2enWupEBtjTgJUwDMvjISMjPQi1N6ZtwjCJD+g0jdl7UzoSmqbgLaId1pk3igKBVT2NWNaY1H6jVoOjUEl7REKBuyB9jpHVhFQPTVEzf3qq2P8+IoOC0W9o6+++jkesGs8HXblZfyI7b24+/53+OtZ7Cdghzpilydv2N6LwSgEhp1lER9AgQgvhlYnUy+OeSSO2JskTqAii09/2aZBL9PQh06++or9j93h7h4oKqpoy9b/2B2+2MW/TJNFuu16Iddq7W0T7py7qE5MH8XjSBqLNkly33qieL/yh5wnXxSnDwu5bdW9YgiFIVC/8fJBnFlyR7x3niZZ4ietetd7qj/CGPwgTG6VSauRzuB9u1WCdQPw2ZVSo+ny08cMxewwZt//TglwdFdbaEj53tSHTM4dIR3pRreYmoEOp970p0jD5nT1m/djztNbehJW24p8yBMQm603BFEZxfsC/cGD6tAbNHf2RV5Xv0WC5YlsKRPoaO1lbHG8xL0HAelxvic4FH8feOFg8MBHAu/rgJ7CYMojKKEKIFDePBx48/lwlgReNEwX8c6DxK0xD2MTff4ffBJ/82cQfv388MXXL7/Z9UZ+wMc9+5X0dL+98t3P3e69F7uQoWfuZ2/uz27F3gvi2/qq7eXvi30jgGraZ7o7fGEfS+/d9amBC3+EyO3zWCzG49DHWFVL4rKCuCvD8pCJ5+6UYelKMBIV8XpOYQ6C3+X3OcEu36qdti5j/EoCc3WkH5SLX8b+NE3iZCEcojYCOiEpQMvNkF2rtNrsIWGzJODiiPjiD5QZinDHW5DyMJuhw2z7q6+OKATivTJ1vUde/15bo8gorRm+GhA0fUyulGgQNzmzNSUR55OcRgA/A5Zr6dGxYj0wAkGpeVJ+OKWik8BNtkDc95fWZOkVLNLovV2gMr9Dqq6qnoXO+K+IXLwpnH0z9y/rfM4Qxs3ZFtpn27sUs/okExd9zaz6ZmXHBN1epav9tuAL9EJVlvEilMZfOmFYarvqlsYUvbcuc25CFvTmbQfIZWlspottnIDtBizwGyzskKWy3oOu7aD1kNzelGpBfFj+/vXLb3quRVAVCbz2kKuzrnvA9ka38ENX1GvoUAa0pnRDmaRuKjenwuudf7Yy6BAcDLN5knppGC3ZIraqp1PW6SiMIunHTxbZIBkPxgtAg8Zbvf1Ijxwi08pZq9GDt5RRaxI/gFaAUxHtcsnkY3RXYpOvPowDXAUU/FBjjGUSSF2xt9q44WJORF6jx6wprdYbilF4Y7B261lROz2jwgmr21R1wMGCEzqMXqQ661CIBR+yy4iDGpWlS+ZNIJk08jKeDpUg1NEuiGmLk0XqaT7zmfqujGzh8lp1RbbXrinFTKzuJYo0SQNmLLUEHKqk75Wu9K9kKyTXqw0VJn8ozGeRSa/VzMu0Fc2WYUAqWVjIxzOZD6Sljxbc+Oq1Y7l5iUqKN9h9HyI6QWIZSGEFlx558WQBoPZ+q0ym17I5JjAp8vWMx7cL8Qz+A/93nD7bHrLzMdJLCY8KQedqrBwOzCDgGQWZAG2Zc++Op7eRN8orrlX4L2cI+sHkdxoISKoIIG5iV2op8tQooVQPJ275hznNoVlVPpNNLeBc1Q3bkiEUQodQ0EnfxckDiRCY468h3tus8Dgn6SpPK/C4+TT1hCxMkSXz0BeuNconfyu8Mc+W7bdU1XKDq5Oa7aRuandVXyk62XxwdcOoRqLWl8X04j5B7k9vYZLROs7tyzQEaJrlADK2QZahjhl1jGgTgtsT+Km3iMN7ngovGhwM5ilEkZm/7FN+1iL2s0XeOFR5zEHAVHuZiJGnGUUECE22bgse9aoRXhE1QqMqkkCi6cz35mHmRcYDUhzG+FTX2OCThcgg3inxvdEikhWMqRoC+YYlLUH3CwP3C/nv13I/lsSF5IHNFhDtpkb1i9NaxymTtw8A+EJ7S39BSHVXhlb1Ne3y0GQ+R/A4MN/FLvM9OdVfFfSNX5OR6EtLsih3Z1SEghKNHUnGEhhVOt+dLgCanwhY/J0OpHU15NL0/ySqcXsVt6lSdZM6vaJuXLwxmJq7YXW4eoziVWxjF8e3YAlbNQP181c72DYyWKCk6Ebb86ls6RY+LYA/JKTdq3kSoZRyrMUQiLmPQeZpU9Lk4p6nHqXfyG9U+ZHdwd7ubn2NbZcmp2tqJ5RuSPVZcEOVkifsYtsdSsvmby+VwMJRqDCfyiyS/0IO+DfgViWbCh1yQs54N83aVkfTXC7sxyQNBgT+q6OohRayC/2qS1yjhTq0zzoLj00N1jDwuF4VNjG7LvFZii9h7+Xzr4cH+Yv8/HB/L38Rv3m+EhicZTayHm8NAtzGcu6rrUQt43meFrPlxkXeVXDMhw8fio8A7/+xEHw2ipbH59DSvIbtnnUFS5fPiuO331p1KD/K5XXZAibia/H/t3dtu2kkafhVStyMHWGMMRkl2SsrJllWieM1jGc14wg3UJieNN1sHyCMZGkfYp9wn2T1H+rQJ2gwtpNR7nzo6q6urvrP//dJVGpeJAtqabr0tKwJYZUEkHlQeOCB6QgNwTcC7599x6QMfrjEwitsusybcdxzmc3zZJSFbrgssdCoSVC1ldLrxOHgxWFdOF4U6M5spLjhYrARagiwfdRoa8mUcUil0lkYfzb+KKcAWC6qs5h7KMu6M7e313h5TJ+o4fM9MHyrFl4XT+pwY/tTeiW/L4nxPDiR/cyKiQOzcQYvhMl76bBl9/xwu0Nj3KLFyTFGSCpmM/vyK8LFsQcerfx4KiM37w29DfyFDFkmIGFQnISOdxQpUj0yxCjM1gG17X9whpwVoIPgUJQbU2tmBM0FivWCCTukuqi8rsCO2N4hALm6+Yzu0PWg5G8isXPJTp1qmmEV26AzS/0P5IkqCIc8hS8vw5+yh+tS6cidGUu0Um0yXH48m8u7Qvco3/E1dH1ymdlUOF46i22H3q8B4S1+Hw3gubYtzQh867XgaeoRhtK2dNHS2FnrWs0eZu+k+tn2WgOZwafSroFenXazibCmpQhUluJE3Wu3x++jWuPpX/ik6gsXqIsy7Nf0VMpi6ebWZ7/0/z7oXlyffeiea0KkEm1kEY+UoQ6inO33e4po4ukX9bTqolbTrfAulkbd17Jfdq4+dnu97qeLwXnnots5t8monoQJhxNIu9BD91nPjZTeCzhKXUNYQCXPXjbxSOM6VoqYZFUj2gNsQeMnuXJGU+mJI7AGJhJ3IsD4jjzpYHbaZMM6/zq77vb/mbQXYfur3zv/+tH5gLDJEEbfdjI4CMw5+wkS/z9AVQoJiMTxBouWnXwuvYD+ESfhMEj9ZRb4gb7yBO39ABN4+TrQMgJ4CmjZWb/UpGfz00G7fdJsDk5ar6y5Zv9u/f4aJggldlh4xz+3Ws2X+ue2+TuOoeoX/OqM7FSBb/E6b3sIPbpAGJBxUyQLNEhl0+adLH6evhHGniiYqBkxc6mGLR/RM9yanFnQz4hXXqEcq3hjGA4Y1ACaT0ulb51EcqCSl9n5V8xd0jCURA9KyiI3srX7OYeVkoNULQ0QnjP3T2Bl51LEAVQfpItky+KTn3hwpuabbwAr0z4sW9q2pvoYeMHdXTWqD14uZUipgfl8VSQrJXJ7Uo4VJnQYjJMRIlaynawKkEO5cIMkyubYymlj8HJKnnJP8VDGMZEs+IkP0A98b6RZqHZf5Piock+EZsSbDnwQQzqrVyEBCUOt/Cs+K32T7FJvzJQB7EuBI8ilsxX9QWqcwPlYbiEa9RtdQr445wKeddkLpEyo2b7pTpi556ygpLQhVEuN3beCdbQfL095OGMoIC15bMbSE/AYOJ46Hg1xKcMJONgqEmdcTCS+xQXf3tfMu404NbAc+sHWjiO/l+0wGj9yP65jjpzh8lQ54bRHnsFBxODIRIZHHasZI7PPgJMesOatrguziyo+dkQ32cZ7fAxH8al8vyee8TfivJU1HTzxavzwur5Xr4urcLXfJUZk3O7b8YJvTx5XvtiputeVdqXqxQNL/1Hkpu3i1ehObFrZOMG6UwVNTX0d0oNirRWSMUZuhGqZcHHlbD51KOD8w//5/vwfU5Sarkit7cuvX+e9o4c+ON3BeS+PFzy3p1bRn7py/DHwHT2iW6X9H/aFdnGjiu7xYLepgrP0eB7vDm4YOT+1StWJSABhOhp4aGlpokNYOFCLmBlDhfAl2b0s8xMnHqMUPTQUwIRyKv0IEJ9GTux4wR08ynbmFk5IPvjUQay5ECjogXNLZ90Y/hzEGaS+3RgnuYsnhnQIKVeMkeQLXDGkpFCLt9kF+1C2iiXMFPtr7tB7Y0Op77rxlUwOLpokJW04fPFUV4L7Jm2K127LDEBD7b+tBUIqiZuq61FnZVoW1kdc05uTajcUt6CSkHJZvRMkDgSPScELoHRTOwj03iB20/y02xZyn+n9GCVDq0YPb3tv2GznoL8JmGGz7QmX4QGEoQKGwtanyhUsnYyD2PEq10724WqrQYNPzoE7UcIUSxKzxGW88X+393CtdTJrNvujWbvvLc7//cr98uvZx5raoDUy0vNagZIj9bTlTht9nov8pIRKzd6GsA9mDrIcmf0FAgeWoebMZOiOUHGgA1hbBQmu7h10YIe1N7WJnDnYoA/2GQAKgNWnhFpun2m2X2fuNsgO95xh1HADozOOi9bjmG9TK9lsv9cmoZRUyhjG+MGw5AIb66B34jOUluS2TU2u/tEatrw/frt+Pf/tbffn7h/dr8P+2fL6/UV88e4qGn+5+vrpvRdeN99ddH0wqFL75KTd2i228iT1QymWn+KCH1wMKELIFtyVlQrzRke+AQhYIiQGHqcDIN3EMt8q5XobuMdOmk3LCHnZtPF+s19x7czNwWetpvoDC+XAFoWGKQRi4jhdO5EeXoN9J4gUTQhevJzDFbFIoNuYLnrbYTokWzg8uWZK72gOw5XyYmnEDrWWRoiMvMBXXQZaLqFxqKenhc9Wk7NG7bQoo8DzqMtr4OYQtjc8Wg+lXPFueyQIc1Wt2cdKD5Gu4FIx3LHsVbEiE5bDAP1JZr6BXz5n5zSgOjzabuv2L0zKvnaHuTnRiO+b9kbh7/dFlcCWrF07OYucmMcKHCtwrF3OW2niBZTIzBC6tj5Re0GMCh+BUuMwkFvoDP3KFxb4QwpZ3hpf4BFhykhFmoQTQ5d4HOmGYBt5sC58uQQ1NHFD4Is3u1y5RANCReDWCqx3DMNgqaRjscPBr3BuT7NSqS5fjs7co+tD9UUqqERrNXauQk8dMtVp99CCdqCJULYtrl6aStd6pOfO3B1K6LfWyUWnQa30GyjyXnseyvoXiw8FtDBmzsSqqM0vvR+rsWOoixn87hl2Y0lJt57Y4/Z/7ONDHocSEtJFKffiD3qF1wun6Ktm5dxRJH2mTwlC984FXwdpXFDixyaqQ1hOimIF04kQfUfCdIgaKoxnLTKptUEcRGB+4S27wAcPP0ACmAIwwQhBxECBHkKmHidu3l/rHEe8dSLZGMuFoNUQAK8GmHGYXhbYXIG8NCHyVIoxOOf+XQKoljSCcahRRlOJgHlOQ/wSMWOeet+fIk32BVQWhBU2CmUs/vef/+KuwTXzscgYOe6B0j61jnopEP8yd6RoWrucKl6nLy4SdQWTyd+E6wNYQ2yvHcbywOiRku3ypdJjezuHVMOKTFCqfnXjiUNoXQ4VbqbH6qhLgT5P05oRndmjHdnSxCYL+D2F6/g0VUiKLWQYAnOwRXHEX7ohPiYQbfQZSy2B+dj0bdkDSZ9M+kFyN9WFSeh16vNcJA4OQieUhw1xbqU5HR8SbvGKimqkv5AeMvqWhrW15LO5w2zRpzbGjiadGV5m0WVtt5+i/OCsPddLnX9i4/TlAjBLuKV1rQHXsSZVCTo2PZtvzozbm9nFh7heG7sRhJ3GNQZZ0b/nmwvztrUCXPhGrbQ81XPxPmYgyOxmLMeBzF1K1I+sBiMoYosh78msbGIG1Laaf0SJCfznESwAB04iUzCH5I+m9yitBT9dvO2gKiRqJ27pdPmEgTRCHeui4I6mwRJavmFSLkqcMrTFzJnJH5mCM5A9MtsxRl9xDHEYjFcw131TRLOKTEk+oSmxGH5PYZEh5fbT8T4niGetbTI6XFG+3KYklaErApPQzeO79fuXPcPVhokO2KAIIKXo4Um3WJ74trmgDIocRtrZSbdSkoiPkH3L3fMo771gKOZgS8ExCSbKYl7NKYDL70PlDOKGuvwbL25qdXFTC0ZhAzqGNSIA/fnFTU2hZiAIQI92QvV6GYAUVoOF43nBEhRHhGBeOIHuGFEdIhnX6YCyYKDVCiLDDhtqqwEoYnuKhXeGb9wdY7yiAFWuux3nB4hWvuE2w+73YF3s7iBbcrnMQS6XXRXU/bfjIXcKbPTn8pDreWL24k/F1OwbteilE8YuorIlmqk9O6ghzvyVCGZuHCuAVDg/npzEIvGZjr3YOgyDmPilXYfUrYRli6U4pv8MWInqR5Vwsu+yoxS3dXpHrUmigeJ7DofwCTfY0/CcV9GS2zKXP0xxVdInWar0Z5TsVdC28l7D5+oaoQgOpFiSMOTFRkmSoWLPCxEd94jiYB6ZLhPo2PHHqZiTHeCYz6UTInQUxnFUpsDcbuoCFiiarFiEEEJZ0QGyxBC9y0TGoykLofedvrDiioa/1s5QkANwCME0qENBIC4gLIF7ghNzNAvCWM7EWA4TLGcDQBPAvZ0HUETlFcS4aGE2irF10oHBTP7iEuqhxkxasWwRK8Zhetumnby1PIEQTsz4hCo5lokZqxJQvoo2TSTosyV+7HriVl3Uw2s6RJHc9XtydCuk58whPKtK7EWrPa0LKIo4bYqxs4ogLJWEyre9C50R4NT642Bpx0NBMTOVOG7/YQDtY6y1cwHkmXuHGlvxBYyDpY9x3JR7jItgwsLodDzAB6aPmDkuPfUtqlBz0QqT+fEXPzJPFaQt3ZnrQ0d2KXbr5etWk8JHKec1WKK8FweMNHhIO8cbq00F7+D6CbmVQ1r9OUA7iaYKVOBxtLSKDtG+Ea9+bjeb4qDVnh7uJShLkiaW0RYCpiehzlbAIJNYyuvJvF41HCeeTgmB3KGyY2hzveWbNODmt+buKZVKqKLmxEJYgrVpQ1wEXLxEGaBJ4jEoGa4rCRQnZmGnb2kT3+H9IU9m+M5B3EAtLPLCRyQDdRDeJacMGAyhcWWssCHHGbWelw3wkrv4A+cm/o/Yqj+Ewh6EgrbJN0eoOjo2hMk4d5ZA90Y6kXJTs7fyTa2B9Z1Vs0OMz3wLWZhblSLKZGpENAMA0bnnjOQ08Maap2A3iQDvhHVwWyZquO54SJQPJmq2Nl9jNQukAm1wNNnWVfclQkOweHNZnYboOKMpsHqGK7SpozUhWPyX2ukzSLCNnBAyuYF5VF3MvSRSeM7cQ4AIo+vTQWrrVMsHWduH1+F5ckGbqxju7/8P7z+q+2adBQA=" + EMBEDDED_SPEC="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" SPEC_TMPFILE="$(mktemp)" trap 'rm -f "$SPEC_TMPFILE"' EXIT echo "$EMBEDDED_SPEC" | base64 --decode | gunzip > "$SPEC_TMPFILE" diff --git a/src/casedev/_client.py b/src/casedev/_client.py index 42aa532d..e418969f 100644 --- a/src/casedev/_client.py +++ b/src/casedev/_client.py @@ -38,47 +38,41 @@ from .resources import ( llm, ocr, - mail, - agent, + linc, legal, media, usage, vault, voice, - format, memory, search, skills, system, compute, matters, - database, - superdoc, webhooks, privilege, translate, + connectors, ) from .resources.system import SystemResource, AsyncSystemResource from .resources.llm.llm import LlmResource, AsyncLlmResource from .resources.ocr.ocr import OcrResource, AsyncOcrResource - from .resources.mail.mail import MailResource, AsyncMailResource - from .resources.agent.agent import AgentResource, AsyncAgentResource + from .resources.linc.linc import LincResource, AsyncLincResource from .resources.legal.legal import LegalResource, AsyncLegalResource from .resources.media.media import MediaResource, AsyncMediaResource from .resources.usage.usage import UsageResource, AsyncUsageResource from .resources.vault.vault import VaultResource, AsyncVaultResource from .resources.voice.voice import VoiceResource, AsyncVoiceResource - from .resources.format.format import FormatResource, AsyncFormatResource from .resources.memory.memory import MemoryResource, AsyncMemoryResource from .resources.search.search import SearchResource, AsyncSearchResource from .resources.skills.skills import SkillsResource, AsyncSkillsResource from .resources.compute.compute import ComputeResource, AsyncComputeResource from .resources.matters.matters import MattersResource, AsyncMattersResource - from .resources.database.database import DatabaseResource, AsyncDatabaseResource - from .resources.superdoc.superdoc import SuperdocResource, AsyncSuperdocResource from .resources.webhooks.webhooks import WebhooksResource, AsyncWebhooksResource from .resources.privilege.privilege import PrivilegeResource, AsyncPrivilegeResource from .resources.translate.translate import TranslateResource, AsyncTranslateResource + from .resources.connectors.connectors import ConnectorsResource, AsyncConnectorsResource __all__ = [ "ENVIRONMENTS", @@ -187,10 +181,10 @@ def __init__( ) @cached_property - def agent(self) -> AgentResource: - from .resources.agent import AgentResource + def connectors(self) -> ConnectorsResource: + from .resources.connectors import ConnectorsResource - return AgentResource(self) + return ConnectorsResource(self) @cached_property def system(self) -> SystemResource: @@ -205,24 +199,18 @@ def compute(self) -> ComputeResource: return ComputeResource(self) - @cached_property - def database(self) -> DatabaseResource: - from .resources.database import DatabaseResource - - return DatabaseResource(self) - - @cached_property - def format(self) -> FormatResource: - from .resources.format import FormatResource - - return FormatResource(self) - @cached_property def legal(self) -> LegalResource: from .resources.legal import LegalResource return LegalResource(self) + @cached_property + def linc(self) -> LincResource: + from .resources.linc import LincResource + + return LincResource(self) + @cached_property def matters(self) -> MattersResource: from .resources.matters import MattersResource @@ -260,12 +248,6 @@ def privilege(self) -> PrivilegeResource: return PrivilegeResource(self) - @cached_property - def mail(self) -> MailResource: - from .resources.mail import MailResource - - return MailResource(self) - @cached_property def skills(self) -> SkillsResource: """Search and read legal AI skills for agents""" @@ -279,12 +261,6 @@ def search(self) -> SearchResource: return SearchResource(self) - @cached_property - def superdoc(self) -> SuperdocResource: - from .resources.superdoc import SuperdocResource - - return SuperdocResource(self) - @cached_property def translate(self) -> TranslateResource: from .resources.translate import TranslateResource @@ -520,10 +496,10 @@ def __init__( ) @cached_property - def agent(self) -> AsyncAgentResource: - from .resources.agent import AsyncAgentResource + def connectors(self) -> AsyncConnectorsResource: + from .resources.connectors import AsyncConnectorsResource - return AsyncAgentResource(self) + return AsyncConnectorsResource(self) @cached_property def system(self) -> AsyncSystemResource: @@ -538,24 +514,18 @@ def compute(self) -> AsyncComputeResource: return AsyncComputeResource(self) - @cached_property - def database(self) -> AsyncDatabaseResource: - from .resources.database import AsyncDatabaseResource - - return AsyncDatabaseResource(self) - - @cached_property - def format(self) -> AsyncFormatResource: - from .resources.format import AsyncFormatResource - - return AsyncFormatResource(self) - @cached_property def legal(self) -> AsyncLegalResource: from .resources.legal import AsyncLegalResource return AsyncLegalResource(self) + @cached_property + def linc(self) -> AsyncLincResource: + from .resources.linc import AsyncLincResource + + return AsyncLincResource(self) + @cached_property def matters(self) -> AsyncMattersResource: from .resources.matters import AsyncMattersResource @@ -593,12 +563,6 @@ def privilege(self) -> AsyncPrivilegeResource: return AsyncPrivilegeResource(self) - @cached_property - def mail(self) -> AsyncMailResource: - from .resources.mail import AsyncMailResource - - return AsyncMailResource(self) - @cached_property def skills(self) -> AsyncSkillsResource: """Search and read legal AI skills for agents""" @@ -612,12 +576,6 @@ def search(self) -> AsyncSearchResource: return AsyncSearchResource(self) - @cached_property - def superdoc(self) -> AsyncSuperdocResource: - from .resources.superdoc import AsyncSuperdocResource - - return AsyncSuperdocResource(self) - @cached_property def translate(self) -> AsyncTranslateResource: from .resources.translate import AsyncTranslateResource @@ -771,10 +729,10 @@ def __init__(self, client: Casedev) -> None: self._client = client @cached_property - def agent(self) -> agent.AgentResourceWithRawResponse: - from .resources.agent import AgentResourceWithRawResponse + def connectors(self) -> connectors.ConnectorsResourceWithRawResponse: + from .resources.connectors import ConnectorsResourceWithRawResponse - return AgentResourceWithRawResponse(self._client.agent) + return ConnectorsResourceWithRawResponse(self._client.connectors) @cached_property def system(self) -> system.SystemResourceWithRawResponse: @@ -789,24 +747,18 @@ def compute(self) -> compute.ComputeResourceWithRawResponse: return ComputeResourceWithRawResponse(self._client.compute) - @cached_property - def database(self) -> database.DatabaseResourceWithRawResponse: - from .resources.database import DatabaseResourceWithRawResponse - - return DatabaseResourceWithRawResponse(self._client.database) - - @cached_property - def format(self) -> format.FormatResourceWithRawResponse: - from .resources.format import FormatResourceWithRawResponse - - return FormatResourceWithRawResponse(self._client.format) - @cached_property def legal(self) -> legal.LegalResourceWithRawResponse: from .resources.legal import LegalResourceWithRawResponse return LegalResourceWithRawResponse(self._client.legal) + @cached_property + def linc(self) -> linc.LincResourceWithRawResponse: + from .resources.linc import LincResourceWithRawResponse + + return LincResourceWithRawResponse(self._client.linc) + @cached_property def matters(self) -> matters.MattersResourceWithRawResponse: from .resources.matters import MattersResourceWithRawResponse @@ -844,12 +796,6 @@ def privilege(self) -> privilege.PrivilegeResourceWithRawResponse: return PrivilegeResourceWithRawResponse(self._client.privilege) - @cached_property - def mail(self) -> mail.MailResourceWithRawResponse: - from .resources.mail import MailResourceWithRawResponse - - return MailResourceWithRawResponse(self._client.mail) - @cached_property def skills(self) -> skills.SkillsResourceWithRawResponse: """Search and read legal AI skills for agents""" @@ -863,12 +809,6 @@ def search(self) -> search.SearchResourceWithRawResponse: return SearchResourceWithRawResponse(self._client.search) - @cached_property - def superdoc(self) -> superdoc.SuperdocResourceWithRawResponse: - from .resources.superdoc import SuperdocResourceWithRawResponse - - return SuperdocResourceWithRawResponse(self._client.superdoc) - @cached_property def translate(self) -> translate.TranslateResourceWithRawResponse: from .resources.translate import TranslateResourceWithRawResponse @@ -908,10 +848,10 @@ def __init__(self, client: AsyncCasedev) -> None: self._client = client @cached_property - def agent(self) -> agent.AsyncAgentResourceWithRawResponse: - from .resources.agent import AsyncAgentResourceWithRawResponse + def connectors(self) -> connectors.AsyncConnectorsResourceWithRawResponse: + from .resources.connectors import AsyncConnectorsResourceWithRawResponse - return AsyncAgentResourceWithRawResponse(self._client.agent) + return AsyncConnectorsResourceWithRawResponse(self._client.connectors) @cached_property def system(self) -> system.AsyncSystemResourceWithRawResponse: @@ -926,24 +866,18 @@ def compute(self) -> compute.AsyncComputeResourceWithRawResponse: return AsyncComputeResourceWithRawResponse(self._client.compute) - @cached_property - def database(self) -> database.AsyncDatabaseResourceWithRawResponse: - from .resources.database import AsyncDatabaseResourceWithRawResponse - - return AsyncDatabaseResourceWithRawResponse(self._client.database) - - @cached_property - def format(self) -> format.AsyncFormatResourceWithRawResponse: - from .resources.format import AsyncFormatResourceWithRawResponse - - return AsyncFormatResourceWithRawResponse(self._client.format) - @cached_property def legal(self) -> legal.AsyncLegalResourceWithRawResponse: from .resources.legal import AsyncLegalResourceWithRawResponse return AsyncLegalResourceWithRawResponse(self._client.legal) + @cached_property + def linc(self) -> linc.AsyncLincResourceWithRawResponse: + from .resources.linc import AsyncLincResourceWithRawResponse + + return AsyncLincResourceWithRawResponse(self._client.linc) + @cached_property def matters(self) -> matters.AsyncMattersResourceWithRawResponse: from .resources.matters import AsyncMattersResourceWithRawResponse @@ -981,12 +915,6 @@ def privilege(self) -> privilege.AsyncPrivilegeResourceWithRawResponse: return AsyncPrivilegeResourceWithRawResponse(self._client.privilege) - @cached_property - def mail(self) -> mail.AsyncMailResourceWithRawResponse: - from .resources.mail import AsyncMailResourceWithRawResponse - - return AsyncMailResourceWithRawResponse(self._client.mail) - @cached_property def skills(self) -> skills.AsyncSkillsResourceWithRawResponse: """Search and read legal AI skills for agents""" @@ -1000,12 +928,6 @@ def search(self) -> search.AsyncSearchResourceWithRawResponse: return AsyncSearchResourceWithRawResponse(self._client.search) - @cached_property - def superdoc(self) -> superdoc.AsyncSuperdocResourceWithRawResponse: - from .resources.superdoc import AsyncSuperdocResourceWithRawResponse - - return AsyncSuperdocResourceWithRawResponse(self._client.superdoc) - @cached_property def translate(self) -> translate.AsyncTranslateResourceWithRawResponse: from .resources.translate import AsyncTranslateResourceWithRawResponse @@ -1045,10 +967,10 @@ def __init__(self, client: Casedev) -> None: self._client = client @cached_property - def agent(self) -> agent.AgentResourceWithStreamingResponse: - from .resources.agent import AgentResourceWithStreamingResponse + def connectors(self) -> connectors.ConnectorsResourceWithStreamingResponse: + from .resources.connectors import ConnectorsResourceWithStreamingResponse - return AgentResourceWithStreamingResponse(self._client.agent) + return ConnectorsResourceWithStreamingResponse(self._client.connectors) @cached_property def system(self) -> system.SystemResourceWithStreamingResponse: @@ -1063,24 +985,18 @@ def compute(self) -> compute.ComputeResourceWithStreamingResponse: return ComputeResourceWithStreamingResponse(self._client.compute) - @cached_property - def database(self) -> database.DatabaseResourceWithStreamingResponse: - from .resources.database import DatabaseResourceWithStreamingResponse - - return DatabaseResourceWithStreamingResponse(self._client.database) - - @cached_property - def format(self) -> format.FormatResourceWithStreamingResponse: - from .resources.format import FormatResourceWithStreamingResponse - - return FormatResourceWithStreamingResponse(self._client.format) - @cached_property def legal(self) -> legal.LegalResourceWithStreamingResponse: from .resources.legal import LegalResourceWithStreamingResponse return LegalResourceWithStreamingResponse(self._client.legal) + @cached_property + def linc(self) -> linc.LincResourceWithStreamingResponse: + from .resources.linc import LincResourceWithStreamingResponse + + return LincResourceWithStreamingResponse(self._client.linc) + @cached_property def matters(self) -> matters.MattersResourceWithStreamingResponse: from .resources.matters import MattersResourceWithStreamingResponse @@ -1118,12 +1034,6 @@ def privilege(self) -> privilege.PrivilegeResourceWithStreamingResponse: return PrivilegeResourceWithStreamingResponse(self._client.privilege) - @cached_property - def mail(self) -> mail.MailResourceWithStreamingResponse: - from .resources.mail import MailResourceWithStreamingResponse - - return MailResourceWithStreamingResponse(self._client.mail) - @cached_property def skills(self) -> skills.SkillsResourceWithStreamingResponse: """Search and read legal AI skills for agents""" @@ -1137,12 +1047,6 @@ def search(self) -> search.SearchResourceWithStreamingResponse: return SearchResourceWithStreamingResponse(self._client.search) - @cached_property - def superdoc(self) -> superdoc.SuperdocResourceWithStreamingResponse: - from .resources.superdoc import SuperdocResourceWithStreamingResponse - - return SuperdocResourceWithStreamingResponse(self._client.superdoc) - @cached_property def translate(self) -> translate.TranslateResourceWithStreamingResponse: from .resources.translate import TranslateResourceWithStreamingResponse @@ -1182,10 +1086,10 @@ def __init__(self, client: AsyncCasedev) -> None: self._client = client @cached_property - def agent(self) -> agent.AsyncAgentResourceWithStreamingResponse: - from .resources.agent import AsyncAgentResourceWithStreamingResponse + def connectors(self) -> connectors.AsyncConnectorsResourceWithStreamingResponse: + from .resources.connectors import AsyncConnectorsResourceWithStreamingResponse - return AsyncAgentResourceWithStreamingResponse(self._client.agent) + return AsyncConnectorsResourceWithStreamingResponse(self._client.connectors) @cached_property def system(self) -> system.AsyncSystemResourceWithStreamingResponse: @@ -1200,24 +1104,18 @@ def compute(self) -> compute.AsyncComputeResourceWithStreamingResponse: return AsyncComputeResourceWithStreamingResponse(self._client.compute) - @cached_property - def database(self) -> database.AsyncDatabaseResourceWithStreamingResponse: - from .resources.database import AsyncDatabaseResourceWithStreamingResponse - - return AsyncDatabaseResourceWithStreamingResponse(self._client.database) - - @cached_property - def format(self) -> format.AsyncFormatResourceWithStreamingResponse: - from .resources.format import AsyncFormatResourceWithStreamingResponse - - return AsyncFormatResourceWithStreamingResponse(self._client.format) - @cached_property def legal(self) -> legal.AsyncLegalResourceWithStreamingResponse: from .resources.legal import AsyncLegalResourceWithStreamingResponse return AsyncLegalResourceWithStreamingResponse(self._client.legal) + @cached_property + def linc(self) -> linc.AsyncLincResourceWithStreamingResponse: + from .resources.linc import AsyncLincResourceWithStreamingResponse + + return AsyncLincResourceWithStreamingResponse(self._client.linc) + @cached_property def matters(self) -> matters.AsyncMattersResourceWithStreamingResponse: from .resources.matters import AsyncMattersResourceWithStreamingResponse @@ -1255,12 +1153,6 @@ def privilege(self) -> privilege.AsyncPrivilegeResourceWithStreamingResponse: return AsyncPrivilegeResourceWithStreamingResponse(self._client.privilege) - @cached_property - def mail(self) -> mail.AsyncMailResourceWithStreamingResponse: - from .resources.mail import AsyncMailResourceWithStreamingResponse - - return AsyncMailResourceWithStreamingResponse(self._client.mail) - @cached_property def skills(self) -> skills.AsyncSkillsResourceWithStreamingResponse: """Search and read legal AI skills for agents""" @@ -1274,12 +1166,6 @@ def search(self) -> search.AsyncSearchResourceWithStreamingResponse: return AsyncSearchResourceWithStreamingResponse(self._client.search) - @cached_property - def superdoc(self) -> superdoc.AsyncSuperdocResourceWithStreamingResponse: - from .resources.superdoc import AsyncSuperdocResourceWithStreamingResponse - - return AsyncSuperdocResourceWithStreamingResponse(self._client.superdoc) - @cached_property def translate(self) -> translate.AsyncTranslateResourceWithStreamingResponse: from .resources.translate import AsyncTranslateResourceWithStreamingResponse diff --git a/src/casedev/_files.py b/src/casedev/_files.py index 76da9e08..9aee1659 100644 --- a/src/casedev/_files.py +++ b/src/casedev/_files.py @@ -36,7 +36,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None: if not is_file_content(obj): prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." + f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/CaseMark/casedev-python/tree/main#file-uploads" ) from None diff --git a/src/casedev/resources/__init__.py b/src/casedev/resources/__init__.py index 0f0b14f6..84699412 100644 --- a/src/casedev/resources/__init__.py +++ b/src/casedev/resources/__init__.py @@ -16,21 +16,13 @@ OcrResourceWithStreamingResponse, AsyncOcrResourceWithStreamingResponse, ) -from .mail import ( - MailResource, - AsyncMailResource, - MailResourceWithRawResponse, - AsyncMailResourceWithRawResponse, - MailResourceWithStreamingResponse, - AsyncMailResourceWithStreamingResponse, -) -from .agent import ( - AgentResource, - AsyncAgentResource, - AgentResourceWithRawResponse, - AsyncAgentResourceWithRawResponse, - AgentResourceWithStreamingResponse, - AsyncAgentResourceWithStreamingResponse, +from .linc import ( + LincResource, + AsyncLincResource, + LincResourceWithRawResponse, + AsyncLincResourceWithRawResponse, + LincResourceWithStreamingResponse, + AsyncLincResourceWithStreamingResponse, ) from .legal import ( LegalResource, @@ -72,14 +64,6 @@ VoiceResourceWithStreamingResponse, AsyncVoiceResourceWithStreamingResponse, ) -from .format import ( - FormatResource, - AsyncFormatResource, - FormatResourceWithRawResponse, - AsyncFormatResourceWithRawResponse, - FormatResourceWithStreamingResponse, - AsyncFormatResourceWithStreamingResponse, -) from .memory import ( MemoryResource, AsyncMemoryResource, @@ -128,22 +112,6 @@ MattersResourceWithStreamingResponse, AsyncMattersResourceWithStreamingResponse, ) -from .database import ( - DatabaseResource, - AsyncDatabaseResource, - DatabaseResourceWithRawResponse, - AsyncDatabaseResourceWithRawResponse, - DatabaseResourceWithStreamingResponse, - AsyncDatabaseResourceWithStreamingResponse, -) -from .superdoc import ( - SuperdocResource, - AsyncSuperdocResource, - SuperdocResourceWithRawResponse, - AsyncSuperdocResourceWithRawResponse, - SuperdocResourceWithStreamingResponse, - AsyncSuperdocResourceWithStreamingResponse, -) from .webhooks import ( WebhooksResource, AsyncWebhooksResource, @@ -168,14 +136,22 @@ TranslateResourceWithStreamingResponse, AsyncTranslateResourceWithStreamingResponse, ) +from .connectors import ( + ConnectorsResource, + AsyncConnectorsResource, + ConnectorsResourceWithRawResponse, + AsyncConnectorsResourceWithRawResponse, + ConnectorsResourceWithStreamingResponse, + AsyncConnectorsResourceWithStreamingResponse, +) __all__ = [ - "AgentResource", - "AsyncAgentResource", - "AgentResourceWithRawResponse", - "AsyncAgentResourceWithRawResponse", - "AgentResourceWithStreamingResponse", - "AsyncAgentResourceWithStreamingResponse", + "ConnectorsResource", + "AsyncConnectorsResource", + "ConnectorsResourceWithRawResponse", + "AsyncConnectorsResourceWithRawResponse", + "ConnectorsResourceWithStreamingResponse", + "AsyncConnectorsResourceWithStreamingResponse", "SystemResource", "AsyncSystemResource", "SystemResourceWithRawResponse", @@ -188,24 +164,18 @@ "AsyncComputeResourceWithRawResponse", "ComputeResourceWithStreamingResponse", "AsyncComputeResourceWithStreamingResponse", - "DatabaseResource", - "AsyncDatabaseResource", - "DatabaseResourceWithRawResponse", - "AsyncDatabaseResourceWithRawResponse", - "DatabaseResourceWithStreamingResponse", - "AsyncDatabaseResourceWithStreamingResponse", - "FormatResource", - "AsyncFormatResource", - "FormatResourceWithRawResponse", - "AsyncFormatResourceWithRawResponse", - "FormatResourceWithStreamingResponse", - "AsyncFormatResourceWithStreamingResponse", "LegalResource", "AsyncLegalResource", "LegalResourceWithRawResponse", "AsyncLegalResourceWithRawResponse", "LegalResourceWithStreamingResponse", "AsyncLegalResourceWithStreamingResponse", + "LincResource", + "AsyncLincResource", + "LincResourceWithRawResponse", + "AsyncLincResourceWithRawResponse", + "LincResourceWithStreamingResponse", + "AsyncLincResourceWithStreamingResponse", "MattersResource", "AsyncMattersResource", "MattersResourceWithRawResponse", @@ -242,12 +212,6 @@ "AsyncPrivilegeResourceWithRawResponse", "PrivilegeResourceWithStreamingResponse", "AsyncPrivilegeResourceWithStreamingResponse", - "MailResource", - "AsyncMailResource", - "MailResourceWithRawResponse", - "AsyncMailResourceWithRawResponse", - "MailResourceWithStreamingResponse", - "AsyncMailResourceWithStreamingResponse", "SkillsResource", "AsyncSkillsResource", "SkillsResourceWithRawResponse", @@ -260,12 +224,6 @@ "AsyncSearchResourceWithRawResponse", "SearchResourceWithStreamingResponse", "AsyncSearchResourceWithStreamingResponse", - "SuperdocResource", - "AsyncSuperdocResource", - "SuperdocResourceWithRawResponse", - "AsyncSuperdocResourceWithRawResponse", - "SuperdocResourceWithStreamingResponse", - "AsyncSuperdocResourceWithStreamingResponse", "TranslateResource", "AsyncTranslateResource", "TranslateResourceWithRawResponse", diff --git a/src/casedev/resources/agent/v1/__init__.py b/src/casedev/resources/agent/v1/__init__.py deleted file mode 100644 index 1c3608c6..00000000 --- a/src/casedev/resources/agent/v1/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .run import ( - RunResource, - AsyncRunResource, - RunResourceWithRawResponse, - AsyncRunResourceWithRawResponse, - RunResourceWithStreamingResponse, - AsyncRunResourceWithStreamingResponse, -) -from .agents import ( - AgentsResource, - AsyncAgentsResource, - AgentsResourceWithRawResponse, - AsyncAgentsResourceWithRawResponse, - AgentsResourceWithStreamingResponse, - AsyncAgentsResourceWithStreamingResponse, -) -from .execute import ( - ExecuteResource, - AsyncExecuteResource, - ExecuteResourceWithRawResponse, - AsyncExecuteResourceWithRawResponse, - ExecuteResourceWithStreamingResponse, - AsyncExecuteResourceWithStreamingResponse, -) - -__all__ = [ - "AgentsResource", - "AsyncAgentsResource", - "AgentsResourceWithRawResponse", - "AsyncAgentsResourceWithRawResponse", - "AgentsResourceWithStreamingResponse", - "AsyncAgentsResourceWithStreamingResponse", - "RunResource", - "AsyncRunResource", - "RunResourceWithRawResponse", - "AsyncRunResourceWithRawResponse", - "RunResourceWithStreamingResponse", - "AsyncRunResourceWithStreamingResponse", - "ExecuteResource", - "AsyncExecuteResource", - "ExecuteResourceWithRawResponse", - "AsyncExecuteResourceWithRawResponse", - "ExecuteResourceWithStreamingResponse", - "AsyncExecuteResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/agent/v1/execute.py b/src/casedev/resources/agent/v1/execute.py deleted file mode 100644 index e78aafba..00000000 --- a/src/casedev/resources/agent/v1/execute.py +++ /dev/null @@ -1,279 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.agent.v1 import execute_create_params -from ....types.agent.v1.execute_create_response import ExecuteCreateResponse - -__all__ = ["ExecuteResource", "AsyncExecuteResource"] - - -class ExecuteResource(SyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - - @cached_property - def with_raw_response(self) -> ExecuteResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return ExecuteResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ExecuteResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return ExecuteResourceWithStreamingResponse(self) - - def create( - self, - *, - prompt: str, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - guidance: Optional[str] | Omit = omit, - instructions: str | Omit = omit, - model: str | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, - sandbox: Optional[execute_create_params.Sandbox] | Omit = omit, - vault_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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ExecuteCreateResponse: - """Creates an ephemeral agent and immediately executes a run. - - Returns the run ID - for polling status and results. This is the fastest way to run an agent without - managing agent lifecycle. - - **Ephemeral agent lifecycle:** The agent created by this endpoint is - automatically soft-deleted and its scoped API key revoked when the run completes - (whether it succeeds, fails, or times out). Ephemeral agents do not appear in - GET /agent/v1/agents listings. The returned agentId is valid only for the - duration of the run — do not store it for reuse. For persistent, reusable - agents, use POST /agent/v1/agents instead. - - Args: - prompt: Task prompt for the agent - - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. - - guidance: Additional context or constraints for this run - - instructions: System instructions. Defaults to a general-purpose legal assistant prompt if not - provided. - - model: LLM model identifier. Defaults to anthropic/claude-sonnet-4.6 - - object_ids: Scope this run to specific vault object IDs. The agent will only access these - objects. - - sandbox: Custom sandbox resources (cpu, memoryMiB) - - vault_ids: Restrict agent to specific vault IDs - - 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( - "/agent/v1/execute", - body=maybe_transform( - { - "prompt": prompt, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "guidance": guidance, - "instructions": instructions, - "model": model, - "object_ids": object_ids, - "sandbox": sandbox, - "vault_ids": vault_ids, - }, - execute_create_params.ExecuteCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ExecuteCreateResponse, - ) - - -class AsyncExecuteResource(AsyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - - @cached_property - def with_raw_response(self) -> AsyncExecuteResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncExecuteResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncExecuteResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncExecuteResourceWithStreamingResponse(self) - - async def create( - self, - *, - prompt: str, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - guidance: Optional[str] | Omit = omit, - instructions: str | Omit = omit, - model: str | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, - sandbox: Optional[execute_create_params.Sandbox] | Omit = omit, - vault_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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ExecuteCreateResponse: - """Creates an ephemeral agent and immediately executes a run. - - Returns the run ID - for polling status and results. This is the fastest way to run an agent without - managing agent lifecycle. - - **Ephemeral agent lifecycle:** The agent created by this endpoint is - automatically soft-deleted and its scoped API key revoked when the run completes - (whether it succeeds, fails, or times out). Ephemeral agents do not appear in - GET /agent/v1/agents listings. The returned agentId is valid only for the - duration of the run — do not store it for reuse. For persistent, reusable - agents, use POST /agent/v1/agents instead. - - Args: - prompt: Task prompt for the agent - - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. - - guidance: Additional context or constraints for this run - - instructions: System instructions. Defaults to a general-purpose legal assistant prompt if not - provided. - - model: LLM model identifier. Defaults to anthropic/claude-sonnet-4.6 - - object_ids: Scope this run to specific vault object IDs. The agent will only access these - objects. - - sandbox: Custom sandbox resources (cpu, memoryMiB) - - vault_ids: Restrict agent to specific vault IDs - - 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( - "/agent/v1/execute", - body=await async_maybe_transform( - { - "prompt": prompt, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "guidance": guidance, - "instructions": instructions, - "model": model, - "object_ids": object_ids, - "sandbox": sandbox, - "vault_ids": vault_ids, - }, - execute_create_params.ExecuteCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ExecuteCreateResponse, - ) - - -class ExecuteResourceWithRawResponse: - def __init__(self, execute: ExecuteResource) -> None: - self._execute = execute - - self.create = to_raw_response_wrapper( - execute.create, - ) - - -class AsyncExecuteResourceWithRawResponse: - def __init__(self, execute: AsyncExecuteResource) -> None: - self._execute = execute - - self.create = async_to_raw_response_wrapper( - execute.create, - ) - - -class ExecuteResourceWithStreamingResponse: - def __init__(self, execute: ExecuteResource) -> None: - self._execute = execute - - self.create = to_streamed_response_wrapper( - execute.create, - ) - - -class AsyncExecuteResourceWithStreamingResponse: - def __init__(self, execute: AsyncExecuteResource) -> None: - self._execute = execute - - self.create = async_to_streamed_response_wrapper( - execute.create, - ) diff --git a/src/casedev/resources/agent/v1/v1.py b/src/casedev/resources/agent/v1/v1.py deleted file mode 100644 index 5d84bf0b..00000000 --- a/src/casedev/resources/agent/v1/v1.py +++ /dev/null @@ -1,220 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .run import ( - RunResource, - AsyncRunResource, - RunResourceWithRawResponse, - AsyncRunResourceWithRawResponse, - RunResourceWithStreamingResponse, - AsyncRunResourceWithStreamingResponse, -) -from .agents import ( - AgentsResource, - AsyncAgentsResource, - AgentsResourceWithRawResponse, - AsyncAgentsResourceWithRawResponse, - AgentsResourceWithStreamingResponse, - AsyncAgentsResourceWithStreamingResponse, -) -from .execute import ( - ExecuteResource, - AsyncExecuteResource, - ExecuteResourceWithRawResponse, - AsyncExecuteResourceWithRawResponse, - ExecuteResourceWithStreamingResponse, - AsyncExecuteResourceWithStreamingResponse, -) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["V1Resource", "AsyncV1Resource"] - - -class V1Resource(SyncAPIResource): - @cached_property - def agents(self) -> AgentsResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AgentsResource(self._client) - - @cached_property - def run(self) -> RunResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return RunResource(self._client) - - @cached_property - def execute(self) -> ExecuteResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return ExecuteResource(self._client) - - @cached_property - def with_raw_response(self) -> V1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return V1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return V1ResourceWithStreamingResponse(self) - - -class AsyncV1Resource(AsyncAPIResource): - @cached_property - def agents(self) -> AsyncAgentsResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncAgentsResource(self._client) - - @cached_property - def run(self) -> AsyncRunResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncRunResource(self._client) - - @cached_property - def execute(self) -> AsyncExecuteResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncExecuteResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncV1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncV1ResourceWithStreamingResponse(self) - - -class V1ResourceWithRawResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - @cached_property - def agents(self) -> AgentsResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AgentsResourceWithRawResponse(self._v1.agents) - - @cached_property - def run(self) -> RunResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return RunResourceWithRawResponse(self._v1.run) - - @cached_property - def execute(self) -> ExecuteResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return ExecuteResourceWithRawResponse(self._v1.execute) - - -class AsyncV1ResourceWithRawResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - @cached_property - def agents(self) -> AsyncAgentsResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncAgentsResourceWithRawResponse(self._v1.agents) - - @cached_property - def run(self) -> AsyncRunResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncRunResourceWithRawResponse(self._v1.run) - - @cached_property - def execute(self) -> AsyncExecuteResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncExecuteResourceWithRawResponse(self._v1.execute) - - -class V1ResourceWithStreamingResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - @cached_property - def agents(self) -> AgentsResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AgentsResourceWithStreamingResponse(self._v1.agents) - - @cached_property - def run(self) -> RunResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return RunResourceWithStreamingResponse(self._v1.run) - - @cached_property - def execute(self) -> ExecuteResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return ExecuteResourceWithStreamingResponse(self._v1.execute) - - -class AsyncV1ResourceWithStreamingResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - @cached_property - def agents(self) -> AsyncAgentsResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncAgentsResourceWithStreamingResponse(self._v1.agents) - - @cached_property - def run(self) -> AsyncRunResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncRunResourceWithStreamingResponse(self._v1.run) - - @cached_property - def execute(self) -> AsyncExecuteResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncExecuteResourceWithStreamingResponse(self._v1.execute) diff --git a/src/casedev/resources/database/__init__.py b/src/casedev/resources/connectors/__init__.py similarity index 50% rename from src/casedev/resources/database/__init__.py rename to src/casedev/resources/connectors/__init__.py index 02eed9d2..a0e9329f 100644 --- a/src/casedev/resources/database/__init__.py +++ b/src/casedev/resources/connectors/__init__.py @@ -8,13 +8,13 @@ V1ResourceWithStreamingResponse, AsyncV1ResourceWithStreamingResponse, ) -from .database import ( - DatabaseResource, - AsyncDatabaseResource, - DatabaseResourceWithRawResponse, - AsyncDatabaseResourceWithRawResponse, - DatabaseResourceWithStreamingResponse, - AsyncDatabaseResourceWithStreamingResponse, +from .connectors import ( + ConnectorsResource, + AsyncConnectorsResource, + ConnectorsResourceWithRawResponse, + AsyncConnectorsResourceWithRawResponse, + ConnectorsResourceWithStreamingResponse, + AsyncConnectorsResourceWithStreamingResponse, ) __all__ = [ @@ -24,10 +24,10 @@ "AsyncV1ResourceWithRawResponse", "V1ResourceWithStreamingResponse", "AsyncV1ResourceWithStreamingResponse", - "DatabaseResource", - "AsyncDatabaseResource", - "DatabaseResourceWithRawResponse", - "AsyncDatabaseResourceWithRawResponse", - "DatabaseResourceWithStreamingResponse", - "AsyncDatabaseResourceWithStreamingResponse", + "ConnectorsResource", + "AsyncConnectorsResource", + "ConnectorsResourceWithRawResponse", + "AsyncConnectorsResourceWithRawResponse", + "ConnectorsResourceWithStreamingResponse", + "AsyncConnectorsResourceWithStreamingResponse", ] diff --git a/src/casedev/resources/agent/agent.py b/src/casedev/resources/connectors/connectors.py similarity index 50% rename from src/casedev/resources/agent/agent.py rename to src/casedev/resources/connectors/connectors.py index 4da17b0d..087107f9 100644 --- a/src/casedev/resources/agent/agent.py +++ b/src/casedev/resources/connectors/connectors.py @@ -13,90 +13,96 @@ from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -__all__ = ["AgentResource", "AsyncAgentResource"] +__all__ = ["ConnectorsResource", "AsyncConnectorsResource"] -class AgentResource(SyncAPIResource): +class ConnectorsResource(SyncAPIResource): @cached_property def v1(self) -> V1Resource: + """Import and export between provider folders (Google Drive) and vaults""" return V1Resource(self._client) @cached_property - def with_raw_response(self) -> AgentResourceWithRawResponse: + def with_raw_response(self) -> ConnectorsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AgentResourceWithRawResponse(self) + return ConnectorsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AgentResourceWithStreamingResponse: + def with_streaming_response(self) -> ConnectorsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AgentResourceWithStreamingResponse(self) + return ConnectorsResourceWithStreamingResponse(self) -class AsyncAgentResource(AsyncAPIResource): +class AsyncConnectorsResource(AsyncAPIResource): @cached_property def v1(self) -> AsyncV1Resource: + """Import and export between provider folders (Google Drive) and vaults""" return AsyncV1Resource(self._client) @cached_property - def with_raw_response(self) -> AsyncAgentResourceWithRawResponse: + def with_raw_response(self) -> AsyncConnectorsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AsyncAgentResourceWithRawResponse(self) + return AsyncConnectorsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncAgentResourceWithStreamingResponse: + def with_streaming_response(self) -> AsyncConnectorsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AsyncAgentResourceWithStreamingResponse(self) + return AsyncConnectorsResourceWithStreamingResponse(self) -class AgentResourceWithRawResponse: - def __init__(self, agent: AgentResource) -> None: - self._agent = agent +class ConnectorsResourceWithRawResponse: + def __init__(self, connectors: ConnectorsResource) -> None: + self._connectors = connectors @cached_property def v1(self) -> V1ResourceWithRawResponse: - return V1ResourceWithRawResponse(self._agent.v1) + """Import and export between provider folders (Google Drive) and vaults""" + return V1ResourceWithRawResponse(self._connectors.v1) -class AsyncAgentResourceWithRawResponse: - def __init__(self, agent: AsyncAgentResource) -> None: - self._agent = agent +class AsyncConnectorsResourceWithRawResponse: + def __init__(self, connectors: AsyncConnectorsResource) -> None: + self._connectors = connectors @cached_property def v1(self) -> AsyncV1ResourceWithRawResponse: - return AsyncV1ResourceWithRawResponse(self._agent.v1) + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncV1ResourceWithRawResponse(self._connectors.v1) -class AgentResourceWithStreamingResponse: - def __init__(self, agent: AgentResource) -> None: - self._agent = agent +class ConnectorsResourceWithStreamingResponse: + def __init__(self, connectors: ConnectorsResource) -> None: + self._connectors = connectors @cached_property def v1(self) -> V1ResourceWithStreamingResponse: - return V1ResourceWithStreamingResponse(self._agent.v1) + """Import and export between provider folders (Google Drive) and vaults""" + return V1ResourceWithStreamingResponse(self._connectors.v1) -class AsyncAgentResourceWithStreamingResponse: - def __init__(self, agent: AsyncAgentResource) -> None: - self._agent = agent +class AsyncConnectorsResourceWithStreamingResponse: + def __init__(self, connectors: AsyncConnectorsResource) -> None: + self._connectors = connectors @cached_property def v1(self) -> AsyncV1ResourceWithStreamingResponse: - return AsyncV1ResourceWithStreamingResponse(self._agent.v1) + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncV1ResourceWithStreamingResponse(self._connectors.v1) diff --git a/src/casedev/resources/connectors/v1/__init__.py b/src/casedev/resources/connectors/v1/__init__.py new file mode 100644 index 00000000..ea1a7d08 --- /dev/null +++ b/src/casedev/resources/connectors/v1/__init__.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .v1 import ( + V1Resource, + AsyncV1Resource, + V1ResourceWithRawResponse, + AsyncV1ResourceWithRawResponse, + V1ResourceWithStreamingResponse, + AsyncV1ResourceWithStreamingResponse, +) +from .links import ( + LinksResource, + AsyncLinksResource, + LinksResourceWithRawResponse, + AsyncLinksResourceWithRawResponse, + LinksResourceWithStreamingResponse, + AsyncLinksResourceWithStreamingResponse, +) +from .connections import ( + ConnectionsResource, + AsyncConnectionsResource, + ConnectionsResourceWithRawResponse, + AsyncConnectionsResourceWithRawResponse, + ConnectionsResourceWithStreamingResponse, + AsyncConnectionsResourceWithStreamingResponse, +) +from .installations import ( + InstallationsResource, + AsyncInstallationsResource, + InstallationsResourceWithRawResponse, + AsyncInstallationsResourceWithRawResponse, + InstallationsResourceWithStreamingResponse, + AsyncInstallationsResourceWithStreamingResponse, +) + +__all__ = [ + "InstallationsResource", + "AsyncInstallationsResource", + "InstallationsResourceWithRawResponse", + "AsyncInstallationsResourceWithRawResponse", + "InstallationsResourceWithStreamingResponse", + "AsyncInstallationsResourceWithStreamingResponse", + "ConnectionsResource", + "AsyncConnectionsResource", + "ConnectionsResourceWithRawResponse", + "AsyncConnectionsResourceWithRawResponse", + "ConnectionsResourceWithStreamingResponse", + "AsyncConnectionsResourceWithStreamingResponse", + "LinksResource", + "AsyncLinksResource", + "LinksResourceWithRawResponse", + "AsyncLinksResourceWithRawResponse", + "LinksResourceWithStreamingResponse", + "AsyncLinksResourceWithStreamingResponse", + "V1Resource", + "AsyncV1Resource", + "V1ResourceWithRawResponse", + "AsyncV1ResourceWithRawResponse", + "V1ResourceWithStreamingResponse", + "AsyncV1ResourceWithStreamingResponse", +] diff --git a/src/casedev/resources/agent/v1/agents.py b/src/casedev/resources/connectors/v1/connections.py similarity index 51% rename from src/casedev/resources/agent/v1/agents.py rename to src/casedev/resources/connectors/v1/connections.py index b2c64567..5799a5ff 100644 --- a/src/casedev/resources/agent/v1/agents.py +++ b/src/casedev/resources/connectors/v1/connections.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing import Optional +from typing_extensions import Literal import httpx -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -17,85 +17,63 @@ async_to_streamed_response_wrapper, ) from ...._base_client import make_request_options -from ....types.agent.v1 import agent_list_params, agent_create_params, agent_update_params -from ....types.agent.v1.agent_list_response import AgentListResponse -from ....types.agent.v1.agent_create_response import AgentCreateResponse -from ....types.agent.v1.agent_delete_response import AgentDeleteResponse -from ....types.agent.v1.agent_update_response import AgentUpdateResponse -from ....types.agent.v1.agent_retrieve_response import AgentRetrieveResponse +from ....types.connectors.v1 import ( + connection_list_params, + connection_browse_params, + connection_create_params, + connection_delete_params, +) +from ....types.connectors.v1.connection_list_response import ConnectionListResponse +from ....types.connectors.v1.connection_browse_response import ConnectionBrowseResponse +from ....types.connectors.v1.connection_create_response import ConnectionCreateResponse -__all__ = ["AgentsResource", "AsyncAgentsResource"] +__all__ = ["ConnectionsResource", "AsyncConnectionsResource"] -class AgentsResource(SyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ +class ConnectionsResource(SyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" @cached_property - def with_raw_response(self) -> AgentsResourceWithRawResponse: + def with_raw_response(self) -> ConnectionsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AgentsResourceWithRawResponse(self) + return ConnectionsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AgentsResourceWithStreamingResponse: + def with_streaming_response(self) -> ConnectionsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AgentsResourceWithStreamingResponse(self) + return ConnectionsResourceWithStreamingResponse(self) def create( self, *, - instructions: str, - name: str, - description: str | Omit = omit, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - model: str | Omit = omit, - sandbox: Optional[agent_create_params.Sandbox] | Omit = omit, - vault_groups: Optional[SequenceNotStr[str]] | Omit = omit, - vault_ids: Optional[SequenceNotStr[str]] | Omit = omit, + provider: Literal["clio", "gdrive", "microsoft"], + return_url: str, + scope_tier: Literal["clio.us", "drive", "microsoft.read"] | 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, - ) -> AgentCreateResponse: - """Creates a new agent definition with a scoped API key. - - The agent can then be used - to create and execute runs. + ) -> ConnectionCreateResponse: + """ + Create a pending provider connection and return a one-time connect_url for the + hosted OAuth flow. The user completes provider consent at connect_url and is + redirected to return_url with ?connection_id=. Args: - instructions: System instructions that define agent behavior - - name: Display name for the agent - - description: Optional description of the agent - - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. - - model: LLM model identifier (e.g. anthropic/claude-sonnet-4.6). Defaults to - anthropic/claude-sonnet-4.6 - - sandbox: Custom sandbox configuration (cpu, memoryMiB) - - vault_groups: Restrict agent to vaults within specific vault group IDs + return_url: HTTPS URL the user is sent back to after consent. - vault_ids: Restrict agent to specific vault IDs + scope_tier: Provider-specific OAuth permission tier. Omit to use the provider's default. extra_headers: Send extra headers @@ -106,25 +84,19 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ return self._post( - "/agent/v1/agents", + "/connectors/v1/connections", body=maybe_transform( { - "instructions": instructions, - "name": name, - "description": description, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "model": model, - "sandbox": sandbox, - "vault_groups": vault_groups, - "vault_ids": vault_ids, + "provider": provider, + "return_url": return_url, + "scope_tier": scope_tier, }, - agent_create_params.AgentCreateParams, + connection_create_params.ConnectionCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AgentCreateResponse, + cast_to=ConnectionCreateResponse, ) def retrieve( @@ -137,9 +109,9 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentRetrieveResponse: + ) -> None: """ - Retrieves a single agent definition by ID. + Retrieve one provider connection, including account identity and health. Args: extra_headers: Send extra headers @@ -152,59 +124,31 @@ def retrieve( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._get( - path_template("/agent/v1/agents/{id}", id=id), + path_template("/connectors/v1/connections/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AgentRetrieveResponse, + cast_to=NoneType, ) - def update( + def list( self, - id: str, *, - description: Optional[str] | Omit = omit, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - instructions: str | Omit = omit, - model: str | Omit = omit, - name: str | Omit = omit, - sandbox: Optional[object] | Omit = omit, - vault_groups: Optional[SequenceNotStr[str]] | Omit = omit, - vault_ids: Optional[SequenceNotStr[str]] | Omit = omit, + provider: str | Omit = omit, + status: Literal["pending", "healthy", "reauth_required", "revoked", "throttled"] | 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, - ) -> AgentUpdateResponse: - """Updates an agent definition. - - Only provided fields are changed. + ) -> ConnectionListResponse: + """ + List provider connections for the organization, with health status. Args: - description: Updated agent description. Pass null to clear if supported by the client. - - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. Pass null to clear. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. Pass null to clear. - - instructions: Updated system instructions that guide agent behavior - - model: Model identifier the agent should use for future runs - - name: Updated agent display name - - sandbox: Sandbox configuration override for future agent runs. Pass null to clear. - - vault_groups: Vault group IDs the agent can access. Pass null to clear. - - vault_ids: Vault IDs the agent can access directly. Pass null to clear. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -213,51 +157,41 @@ def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._patch( - path_template("/agent/v1/agents/{id}", id=id), - body=maybe_transform( - { - "description": description, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "instructions": instructions, - "model": model, - "name": name, - "sandbox": sandbox, - "vault_groups": vault_groups, - "vault_ids": vault_ids, - }, - agent_update_params.AgentUpdateParams, - ), + return self._get( + "/connectors/v1/connections", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "provider": provider, + "status": status, + }, + connection_list_params.ConnectionListParams, + ), ), - cast_to=AgentUpdateResponse, + cast_to=ConnectionListResponse, ) - def list( + def delete( self, + id: str, *, - cursor: str | Omit = omit, - limit: int | Omit = omit, + purge: bool | 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, - ) -> AgentListResponse: + ) -> None: """ - Lists all active agents for the authenticated organization. + Unlink a provider account: revoke tokens at the provider and delete them. + purge=true additionally deletes the vault documents its import links brought in. Args: - cursor: Pagination cursor (agent ID from previous page). Returns agents created before - this agent. - - limit: Maximum number of agents to return (default 50, max 250) - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -266,39 +200,54 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get( - "/agent/v1/agents", + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/connectors/v1/connections/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - agent_list_params.AgentListParams, - ), + query=maybe_transform({"purge": purge}, connection_delete_params.ConnectionDeleteParams), ), - cast_to=AgentListResponse, + cast_to=NoneType, ) - def delete( + def browse( self, id: str, *, + container: str | Omit = omit, + cursor: str | Omit = omit, + page_size: int | Omit = omit, + parent: str | Omit = omit, + query: str | Omit = omit, + site: 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, - ) -> AgentDeleteResponse: - """ - Soft-deletes an agent and revokes its scoped API key. + ) -> ConnectionBrowseResponse: + """Browse the provider one level at a time. + + Without a site, container, or parent, + returns top-level resources. Pass the stable browse_ref fields returned by one + response to navigate into the next level. Returns 403 + provider_scope_insufficient when the connection scope cannot browse server-side. Args: + container: Container id to list, or the container containing parent + + parent: Folder id to list + + query: Optional provider-supported search text + + site: Site id to list + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -309,84 +258,73 @@ def delete( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - path_template("/agent/v1/agents/{id}", id=id), + return self._get( + path_template("/connectors/v1/connections/{id}/browse", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "container": container, + "cursor": cursor, + "page_size": page_size, + "parent": parent, + "query": query, + "site": site, + }, + connection_browse_params.ConnectionBrowseParams, + ), ), - cast_to=AgentDeleteResponse, + cast_to=ConnectionBrowseResponse, ) -class AsyncAgentsResource(AsyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ +class AsyncConnectionsResource(AsyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" @cached_property - def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse: + def with_raw_response(self) -> AsyncConnectionsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AsyncAgentsResourceWithRawResponse(self) + return AsyncConnectionsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse: + def with_streaming_response(self) -> AsyncConnectionsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AsyncAgentsResourceWithStreamingResponse(self) + return AsyncConnectionsResourceWithStreamingResponse(self) async def create( self, *, - instructions: str, - name: str, - description: str | Omit = omit, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - model: str | Omit = omit, - sandbox: Optional[agent_create_params.Sandbox] | Omit = omit, - vault_groups: Optional[SequenceNotStr[str]] | Omit = omit, - vault_ids: Optional[SequenceNotStr[str]] | Omit = omit, + provider: Literal["clio", "gdrive", "microsoft"], + return_url: str, + scope_tier: Literal["clio.us", "drive", "microsoft.read"] | 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, - ) -> AgentCreateResponse: - """Creates a new agent definition with a scoped API key. - - The agent can then be used - to create and execute runs. + ) -> ConnectionCreateResponse: + """ + Create a pending provider connection and return a one-time connect_url for the + hosted OAuth flow. The user completes provider consent at connect_url and is + redirected to return_url with ?connection_id=. Args: - instructions: System instructions that define agent behavior - - name: Display name for the agent - - description: Optional description of the agent + return_url: HTTPS URL the user is sent back to after consent. - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. - - model: LLM model identifier (e.g. anthropic/claude-sonnet-4.6). Defaults to - anthropic/claude-sonnet-4.6 - - sandbox: Custom sandbox configuration (cpu, memoryMiB) - - vault_groups: Restrict agent to vaults within specific vault group IDs - - vault_ids: Restrict agent to specific vault IDs + scope_tier: Provider-specific OAuth permission tier. Omit to use the provider's default. extra_headers: Send extra headers @@ -397,25 +335,19 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ return await self._post( - "/agent/v1/agents", + "/connectors/v1/connections", body=await async_maybe_transform( { - "instructions": instructions, - "name": name, - "description": description, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "model": model, - "sandbox": sandbox, - "vault_groups": vault_groups, - "vault_ids": vault_ids, + "provider": provider, + "return_url": return_url, + "scope_tier": scope_tier, }, - agent_create_params.AgentCreateParams, + connection_create_params.ConnectionCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AgentCreateResponse, + cast_to=ConnectionCreateResponse, ) async def retrieve( @@ -428,9 +360,9 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentRetrieveResponse: + ) -> None: """ - Retrieves a single agent definition by ID. + Retrieve one provider connection, including account identity and health. Args: extra_headers: Send extra headers @@ -443,59 +375,31 @@ async def retrieve( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._get( - path_template("/agent/v1/agents/{id}", id=id), + path_template("/connectors/v1/connections/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AgentRetrieveResponse, + cast_to=NoneType, ) - async def update( + async def list( self, - id: str, *, - description: Optional[str] | Omit = omit, - disabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - enabled_tools: Optional[SequenceNotStr[str]] | Omit = omit, - instructions: str | Omit = omit, - model: str | Omit = omit, - name: str | Omit = omit, - sandbox: Optional[object] | Omit = omit, - vault_groups: Optional[SequenceNotStr[str]] | Omit = omit, - vault_ids: Optional[SequenceNotStr[str]] | Omit = omit, + provider: str | Omit = omit, + status: Literal["pending", "healthy", "reauth_required", "revoked", "throttled"] | 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, - ) -> AgentUpdateResponse: - """Updates an agent definition. - - Only provided fields are changed. + ) -> ConnectionListResponse: + """ + List provider connections for the organization, with health status. Args: - description: Updated agent description. Pass null to clear if supported by the client. - - disabled_tools: Denylist of tools the agent cannot use. Mutually exclusive with enabledTools — - set one or the other, not both. Pass null to clear. - - enabled_tools: Allowlist of tools the agent can use. Mutually exclusive with disabledTools — - set one or the other, not both. Pass null to clear. - - instructions: Updated system instructions that guide agent behavior - - model: Model identifier the agent should use for future runs - - name: Updated agent display name - - sandbox: Sandbox configuration override for future agent runs. Pass null to clear. - - vault_groups: Vault group IDs the agent can access. Pass null to clear. - - vault_ids: Vault IDs the agent can access directly. Pass null to clear. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -504,51 +408,41 @@ async def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._patch( - path_template("/agent/v1/agents/{id}", id=id), - body=await async_maybe_transform( - { - "description": description, - "disabled_tools": disabled_tools, - "enabled_tools": enabled_tools, - "instructions": instructions, - "model": model, - "name": name, - "sandbox": sandbox, - "vault_groups": vault_groups, - "vault_ids": vault_ids, - }, - agent_update_params.AgentUpdateParams, - ), + return await self._get( + "/connectors/v1/connections", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "provider": provider, + "status": status, + }, + connection_list_params.ConnectionListParams, + ), ), - cast_to=AgentUpdateResponse, + cast_to=ConnectionListResponse, ) - async def list( + async def delete( self, + id: str, *, - cursor: str | Omit = omit, - limit: int | Omit = omit, + purge: bool | 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, - ) -> AgentListResponse: + ) -> None: """ - Lists all active agents for the authenticated organization. + Unlink a provider account: revoke tokens at the provider and delete them. + purge=true additionally deletes the vault documents its import links brought in. Args: - cursor: Pagination cursor (agent ID from previous page). Returns agents created before - this agent. - - limit: Maximum number of agents to return (default 50, max 250) - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -557,39 +451,54 @@ async def list( timeout: Override the client-level default timeout for this request, in seconds """ - return await self._get( - "/agent/v1/agents", + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/connectors/v1/connections/{id}", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - agent_list_params.AgentListParams, - ), + query=await async_maybe_transform({"purge": purge}, connection_delete_params.ConnectionDeleteParams), ), - cast_to=AgentListResponse, + cast_to=NoneType, ) - async def delete( + async def browse( self, id: str, *, + container: str | Omit = omit, + cursor: str | Omit = omit, + page_size: int | Omit = omit, + parent: str | Omit = omit, + query: str | Omit = omit, + site: 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, - ) -> AgentDeleteResponse: - """ - Soft-deletes an agent and revokes its scoped API key. + ) -> ConnectionBrowseResponse: + """Browse the provider one level at a time. + + Without a site, container, or parent, + returns top-level resources. Pass the stable browse_ref fields returned by one + response to navigate into the next level. Returns 403 + provider_scope_insufficient when the connection scope cannot browse server-side. Args: + container: Container id to list, or the container containing parent + + parent: Folder id to list + + query: Optional provider-supported search text + + site: Site id to list + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -600,94 +509,108 @@ async def delete( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - path_template("/agent/v1/agents/{id}", id=id), + return await self._get( + path_template("/connectors/v1/connections/{id}/browse", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "container": container, + "cursor": cursor, + "page_size": page_size, + "parent": parent, + "query": query, + "site": site, + }, + connection_browse_params.ConnectionBrowseParams, + ), ), - cast_to=AgentDeleteResponse, + cast_to=ConnectionBrowseResponse, ) -class AgentsResourceWithRawResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents +class ConnectionsResourceWithRawResponse: + def __init__(self, connections: ConnectionsResource) -> None: + self._connections = connections self.create = to_raw_response_wrapper( - agents.create, + connections.create, ) self.retrieve = to_raw_response_wrapper( - agents.retrieve, - ) - self.update = to_raw_response_wrapper( - agents.update, + connections.retrieve, ) self.list = to_raw_response_wrapper( - agents.list, + connections.list, ) self.delete = to_raw_response_wrapper( - agents.delete, + connections.delete, + ) + self.browse = to_raw_response_wrapper( + connections.browse, ) -class AsyncAgentsResourceWithRawResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents +class AsyncConnectionsResourceWithRawResponse: + def __init__(self, connections: AsyncConnectionsResource) -> None: + self._connections = connections self.create = async_to_raw_response_wrapper( - agents.create, + connections.create, ) self.retrieve = async_to_raw_response_wrapper( - agents.retrieve, - ) - self.update = async_to_raw_response_wrapper( - agents.update, + connections.retrieve, ) self.list = async_to_raw_response_wrapper( - agents.list, + connections.list, ) self.delete = async_to_raw_response_wrapper( - agents.delete, + connections.delete, + ) + self.browse = async_to_raw_response_wrapper( + connections.browse, ) -class AgentsResourceWithStreamingResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents +class ConnectionsResourceWithStreamingResponse: + def __init__(self, connections: ConnectionsResource) -> None: + self._connections = connections self.create = to_streamed_response_wrapper( - agents.create, + connections.create, ) self.retrieve = to_streamed_response_wrapper( - agents.retrieve, - ) - self.update = to_streamed_response_wrapper( - agents.update, + connections.retrieve, ) self.list = to_streamed_response_wrapper( - agents.list, + connections.list, ) self.delete = to_streamed_response_wrapper( - agents.delete, + connections.delete, + ) + self.browse = to_streamed_response_wrapper( + connections.browse, ) -class AsyncAgentsResourceWithStreamingResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents +class AsyncConnectionsResourceWithStreamingResponse: + def __init__(self, connections: AsyncConnectionsResource) -> None: + self._connections = connections self.create = async_to_streamed_response_wrapper( - agents.create, + connections.create, ) self.retrieve = async_to_streamed_response_wrapper( - agents.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - agents.update, + connections.retrieve, ) self.list = async_to_streamed_response_wrapper( - agents.list, + connections.list, ) self.delete = async_to_streamed_response_wrapper( - agents.delete, + connections.delete, + ) + self.browse = async_to_streamed_response_wrapper( + connections.browse, ) diff --git a/src/casedev/resources/connectors/v1/installations/__init__.py b/src/casedev/resources/connectors/v1/installations/__init__.py new file mode 100644 index 00000000..5a4ab57a --- /dev/null +++ b/src/casedev/resources/connectors/v1/installations/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .vaults import ( + VaultsResource, + AsyncVaultsResource, + VaultsResourceWithRawResponse, + AsyncVaultsResourceWithRawResponse, + VaultsResourceWithStreamingResponse, + AsyncVaultsResourceWithStreamingResponse, +) +from .installations import ( + InstallationsResource, + AsyncInstallationsResource, + InstallationsResourceWithRawResponse, + AsyncInstallationsResourceWithRawResponse, + InstallationsResourceWithStreamingResponse, + AsyncInstallationsResourceWithStreamingResponse, +) + +__all__ = [ + "VaultsResource", + "AsyncVaultsResource", + "VaultsResourceWithRawResponse", + "AsyncVaultsResourceWithRawResponse", + "VaultsResourceWithStreamingResponse", + "AsyncVaultsResourceWithStreamingResponse", + "InstallationsResource", + "AsyncInstallationsResource", + "InstallationsResourceWithRawResponse", + "AsyncInstallationsResourceWithRawResponse", + "InstallationsResourceWithStreamingResponse", + "AsyncInstallationsResourceWithStreamingResponse", +] diff --git a/src/casedev/resources/connectors/v1/installations/installations.py b/src/casedev/resources/connectors/v1/installations/installations.py new file mode 100644 index 00000000..e7e51664 --- /dev/null +++ b/src/casedev/resources/connectors/v1/installations/installations.py @@ -0,0 +1,330 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .vaults import ( + VaultsResource, + AsyncVaultsResource, + VaultsResourceWithRawResponse, + AsyncVaultsResourceWithRawResponse, + VaultsResourceWithStreamingResponse, + AsyncVaultsResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.connectors.v1 import installation_list_params, installation_ensure_params + +__all__ = ["InstallationsResource", "AsyncInstallationsResource"] + + +class InstallationsResource(SyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def vaults(self) -> VaultsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return VaultsResource(self._client) + + @cached_property + def with_raw_response(self) -> InstallationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return InstallationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> InstallationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return InstallationsResourceWithStreamingResponse(self) + + def list( + self, + *, + application: str | Omit = omit, + external_tenant_id: 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, + ) -> None: + """ + List application installations (tenants) in this organization. + + 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._get( + "/connectors/v1/installations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "application": application, + "external_tenant_id": external_tenant_id, + }, + installation_list_params.InstallationListParams, + ), + ), + cast_to=NoneType, + ) + + def ensure( + self, + *, + application: str, + external_tenant_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, + ) -> None: + """ + Idempotently create (or return) the installation for (application, + external_tenant_id) in this organization. Send the returned installation id as + X-Case-Installation-Id on connector requests to scope them to this tenant. + + Args: + application: Consuming application key (e.g. "p3"). + + external_tenant_id: The application's own tenant identifier (e.g. a P3 organization id). + + 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( + "/connectors/v1/installations", + body=maybe_transform( + { + "application": application, + "external_tenant_id": external_tenant_id, + }, + installation_ensure_params.InstallationEnsureParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncInstallationsResource(AsyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def vaults(self) -> AsyncVaultsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncVaultsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncInstallationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return AsyncInstallationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncInstallationsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return AsyncInstallationsResourceWithStreamingResponse(self) + + async def list( + self, + *, + application: str | Omit = omit, + external_tenant_id: 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, + ) -> None: + """ + List application installations (tenants) in this organization. + + 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._get( + "/connectors/v1/installations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "application": application, + "external_tenant_id": external_tenant_id, + }, + installation_list_params.InstallationListParams, + ), + ), + cast_to=NoneType, + ) + + async def ensure( + self, + *, + application: str, + external_tenant_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, + ) -> None: + """ + Idempotently create (or return) the installation for (application, + external_tenant_id) in this organization. Send the returned installation id as + X-Case-Installation-Id on connector requests to scope them to this tenant. + + Args: + application: Consuming application key (e.g. "p3"). + + external_tenant_id: The application's own tenant identifier (e.g. a P3 organization id). + + 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( + "/connectors/v1/installations", + body=await async_maybe_transform( + { + "application": application, + "external_tenant_id": external_tenant_id, + }, + installation_ensure_params.InstallationEnsureParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class InstallationsResourceWithRawResponse: + def __init__(self, installations: InstallationsResource) -> None: + self._installations = installations + + self.list = to_raw_response_wrapper( + installations.list, + ) + self.ensure = to_raw_response_wrapper( + installations.ensure, + ) + + @cached_property + def vaults(self) -> VaultsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return VaultsResourceWithRawResponse(self._installations.vaults) + + +class AsyncInstallationsResourceWithRawResponse: + def __init__(self, installations: AsyncInstallationsResource) -> None: + self._installations = installations + + self.list = async_to_raw_response_wrapper( + installations.list, + ) + self.ensure = async_to_raw_response_wrapper( + installations.ensure, + ) + + @cached_property + def vaults(self) -> AsyncVaultsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncVaultsResourceWithRawResponse(self._installations.vaults) + + +class InstallationsResourceWithStreamingResponse: + def __init__(self, installations: InstallationsResource) -> None: + self._installations = installations + + self.list = to_streamed_response_wrapper( + installations.list, + ) + self.ensure = to_streamed_response_wrapper( + installations.ensure, + ) + + @cached_property + def vaults(self) -> VaultsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return VaultsResourceWithStreamingResponse(self._installations.vaults) + + +class AsyncInstallationsResourceWithStreamingResponse: + def __init__(self, installations: AsyncInstallationsResource) -> None: + self._installations = installations + + self.list = async_to_streamed_response_wrapper( + installations.list, + ) + self.ensure = async_to_streamed_response_wrapper( + installations.ensure, + ) + + @cached_property + def vaults(self) -> AsyncVaultsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncVaultsResourceWithStreamingResponse(self._installations.vaults) diff --git a/src/casedev/resources/vault/graphrag.py b/src/casedev/resources/connectors/v1/installations/vaults.py similarity index 53% rename from src/casedev/resources/vault/graphrag.py rename to src/casedev/resources/connectors/v1/installations/vaults.py index 7e214417..eef851eb 100644 --- a/src/casedev/resources/vault/graphrag.py +++ b/src/casedev/resources/connectors/v1/installations/vaults.py @@ -2,49 +2,49 @@ from __future__ import annotations +from typing_extensions import Literal + 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 ( +from ....._types import Body, Omit, Query, Headers, NoneType, 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 ( to_raw_response_wrapper, to_streamed_response_wrapper, async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ..._base_client import make_request_options -from ...types.vault.graphrag_init_response import GraphragInitResponse -from ...types.vault.graphrag_get_stats_response import GraphragGetStatsResponse -from ...types.vault.graphrag_process_object_response import GraphragProcessObjectResponse +from ....._base_client import make_request_options +from .....types.connectors.v1.installations import vault_grant_params -__all__ = ["GraphragResource", "AsyncGraphragResource"] +__all__ = ["VaultsResource", "AsyncVaultsResource"] -class GraphragResource(SyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" +class VaultsResource(SyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" @cached_property - def with_raw_response(self) -> GraphragResourceWithRawResponse: + def with_raw_response(self) -> VaultsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return GraphragResourceWithRawResponse(self) + return VaultsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> GraphragResourceWithStreamingResponse: + def with_streaming_response(self) -> VaultsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return GraphragResourceWithStreamingResponse(self) + return VaultsResourceWithStreamingResponse(self) - def get_stats( + def list( self, id: str, *, @@ -54,12 +54,9 @@ def get_stats( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraphragGetStatsResponse: + ) -> None: """ - Retrieve GraphRAG (Graph Retrieval-Augmented Generation) statistics for a - specific vault. This includes metrics about the knowledge graph structure, - entity relationships, and processing status that enable advanced semantic search - and AI-powered document analysis. + List the vaults an installation may use, with capabilities and revocation state. Args: extra_headers: Send extra headers @@ -72,30 +69,37 @@ def get_stats( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._get( - path_template("/vault/{id}/graphrag/stats", id=id), + path_template("/connectors/v1/installations/{id}/vaults", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragGetStatsResponse, + cast_to=NoneType, ) - def init( + def grant( self, - id: str, + vault_id: str, *, + id: str, + can_manage: bool | Omit = omit, + can_read: bool | Omit = omit, + can_write: bool | Omit = omit, + relationship: Literal["owned", "shared"] | Omit = omit, + source: Literal["provisioning", "lazy_reconcile", "explicit_share"] | 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, - ) -> GraphragInitResponse: - """ - Initialize a GraphRAG workspace for a vault to enable advanced knowledge graph - and retrieval-augmented generation capabilities. This creates the necessary - infrastructure for semantic document analysis and graph-based querying within - the vault. + ) -> None: + """Grant (or update) an installation's access to a vault. + + Re-granting a revoked + vault reactivates it. Import links need can_write; export links need can_read; + mirror deletion and purge need can_manage. Args: extra_headers: Send extra headers @@ -108,17 +112,30 @@ def init( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - path_template("/vault/{id}/graphrag/init", id=id), + if not vault_id: + raise ValueError(f"Expected a non-empty value for `vault_id` but received {vault_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._put( + path_template("/connectors/v1/installations/{id}/vaults/{vault_id}", id=id, vault_id=vault_id), + body=maybe_transform( + { + "can_manage": can_manage, + "can_read": can_read, + "can_write": can_write, + "relationship": relationship, + "source": source, + }, + vault_grant_params.VaultGrantParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragInitResponse, + cast_to=NoneType, ) - def process_object( + def revoke( self, - object_id: str, + vault_id: str, *, id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -127,12 +144,11 @@ def process_object( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraphragProcessObjectResponse: - """Manually trigger GraphRAG indexing for a vault object. + ) -> None: + """Revoke an installation's access to a vault. - The object must already - be ingested (completed status). This extracts entities, relationships, and - communities from the document for advanced knowledge graph queries. + Links using the vault pause at their + next run; nothing is deleted. Args: extra_headers: Send extra headers @@ -145,40 +161,41 @@ def process_object( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not object_id: - raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - return self._post( - path_template("/vault/{id}/graphrag/{object_id}", id=id, object_id=object_id), + if not vault_id: + raise ValueError(f"Expected a non-empty value for `vault_id` but received {vault_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/connectors/v1/installations/{id}/vaults/{vault_id}", id=id, vault_id=vault_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragProcessObjectResponse, + cast_to=NoneType, ) -class AsyncGraphragResource(AsyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" +class AsyncVaultsResource(AsyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" @cached_property - def with_raw_response(self) -> AsyncGraphragResourceWithRawResponse: + def with_raw_response(self) -> AsyncVaultsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AsyncGraphragResourceWithRawResponse(self) + return AsyncVaultsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncGraphragResourceWithStreamingResponse: + def with_streaming_response(self) -> AsyncVaultsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AsyncGraphragResourceWithStreamingResponse(self) + return AsyncVaultsResourceWithStreamingResponse(self) - async def get_stats( + async def list( self, id: str, *, @@ -188,12 +205,9 @@ async def get_stats( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraphragGetStatsResponse: + ) -> None: """ - Retrieve GraphRAG (Graph Retrieval-Augmented Generation) statistics for a - specific vault. This includes metrics about the knowledge graph structure, - entity relationships, and processing status that enable advanced semantic search - and AI-powered document analysis. + List the vaults an installation may use, with capabilities and revocation state. Args: extra_headers: Send extra headers @@ -206,30 +220,37 @@ async def get_stats( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._get( - path_template("/vault/{id}/graphrag/stats", id=id), + path_template("/connectors/v1/installations/{id}/vaults", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragGetStatsResponse, + cast_to=NoneType, ) - async def init( + async def grant( self, - id: str, + vault_id: str, *, + id: str, + can_manage: bool | Omit = omit, + can_read: bool | Omit = omit, + can_write: bool | Omit = omit, + relationship: Literal["owned", "shared"] | Omit = omit, + source: Literal["provisioning", "lazy_reconcile", "explicit_share"] | 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, - ) -> GraphragInitResponse: - """ - Initialize a GraphRAG workspace for a vault to enable advanced knowledge graph - and retrieval-augmented generation capabilities. This creates the necessary - infrastructure for semantic document analysis and graph-based querying within - the vault. + ) -> None: + """Grant (or update) an installation's access to a vault. + + Re-granting a revoked + vault reactivates it. Import links need can_write; export links need can_read; + mirror deletion and purge need can_manage. Args: extra_headers: Send extra headers @@ -242,17 +263,30 @@ async def init( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - path_template("/vault/{id}/graphrag/init", id=id), + if not vault_id: + raise ValueError(f"Expected a non-empty value for `vault_id` but received {vault_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._put( + path_template("/connectors/v1/installations/{id}/vaults/{vault_id}", id=id, vault_id=vault_id), + body=await async_maybe_transform( + { + "can_manage": can_manage, + "can_read": can_read, + "can_write": can_write, + "relationship": relationship, + "source": source, + }, + vault_grant_params.VaultGrantParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragInitResponse, + cast_to=NoneType, ) - async def process_object( + async def revoke( self, - object_id: str, + vault_id: str, *, id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -261,12 +295,11 @@ async def process_object( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> GraphragProcessObjectResponse: - """Manually trigger GraphRAG indexing for a vault object. + ) -> None: + """Revoke an installation's access to a vault. - The object must already - be ingested (completed status). This extracts entities, relationships, and - communities from the document for advanced knowledge graph queries. + Links using the vault pause at their + next run; nothing is deleted. Args: extra_headers: Send extra headers @@ -279,72 +312,73 @@ async def process_object( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not object_id: - raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - return await self._post( - path_template("/vault/{id}/graphrag/{object_id}", id=id, object_id=object_id), + if not vault_id: + raise ValueError(f"Expected a non-empty value for `vault_id` but received {vault_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/connectors/v1/installations/{id}/vaults/{vault_id}", id=id, vault_id=vault_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GraphragProcessObjectResponse, + cast_to=NoneType, ) -class GraphragResourceWithRawResponse: - def __init__(self, graphrag: GraphragResource) -> None: - self._graphrag = graphrag +class VaultsResourceWithRawResponse: + def __init__(self, vaults: VaultsResource) -> None: + self._vaults = vaults - self.get_stats = to_raw_response_wrapper( - graphrag.get_stats, + self.list = to_raw_response_wrapper( + vaults.list, ) - self.init = to_raw_response_wrapper( - graphrag.init, + self.grant = to_raw_response_wrapper( + vaults.grant, ) - self.process_object = to_raw_response_wrapper( - graphrag.process_object, + self.revoke = to_raw_response_wrapper( + vaults.revoke, ) -class AsyncGraphragResourceWithRawResponse: - def __init__(self, graphrag: AsyncGraphragResource) -> None: - self._graphrag = graphrag +class AsyncVaultsResourceWithRawResponse: + def __init__(self, vaults: AsyncVaultsResource) -> None: + self._vaults = vaults - self.get_stats = async_to_raw_response_wrapper( - graphrag.get_stats, + self.list = async_to_raw_response_wrapper( + vaults.list, ) - self.init = async_to_raw_response_wrapper( - graphrag.init, + self.grant = async_to_raw_response_wrapper( + vaults.grant, ) - self.process_object = async_to_raw_response_wrapper( - graphrag.process_object, + self.revoke = async_to_raw_response_wrapper( + vaults.revoke, ) -class GraphragResourceWithStreamingResponse: - def __init__(self, graphrag: GraphragResource) -> None: - self._graphrag = graphrag +class VaultsResourceWithStreamingResponse: + def __init__(self, vaults: VaultsResource) -> None: + self._vaults = vaults - self.get_stats = to_streamed_response_wrapper( - graphrag.get_stats, + self.list = to_streamed_response_wrapper( + vaults.list, ) - self.init = to_streamed_response_wrapper( - graphrag.init, + self.grant = to_streamed_response_wrapper( + vaults.grant, ) - self.process_object = to_streamed_response_wrapper( - graphrag.process_object, + self.revoke = to_streamed_response_wrapper( + vaults.revoke, ) -class AsyncGraphragResourceWithStreamingResponse: - def __init__(self, graphrag: AsyncGraphragResource) -> None: - self._graphrag = graphrag +class AsyncVaultsResourceWithStreamingResponse: + def __init__(self, vaults: AsyncVaultsResource) -> None: + self._vaults = vaults - self.get_stats = async_to_streamed_response_wrapper( - graphrag.get_stats, + self.list = async_to_streamed_response_wrapper( + vaults.list, ) - self.init = async_to_streamed_response_wrapper( - graphrag.init, + self.grant = async_to_streamed_response_wrapper( + vaults.grant, ) - self.process_object = async_to_streamed_response_wrapper( - graphrag.process_object, + self.revoke = async_to_streamed_response_wrapper( + vaults.revoke, ) diff --git a/src/casedev/resources/connectors/v1/links.py b/src/casedev/resources/connectors/v1/links.py new file mode 100644 index 00000000..7c93bbb4 --- /dev/null +++ b/src/casedev/resources/connectors/v1/links.py @@ -0,0 +1,598 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, 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 ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.connectors.v1 import link_list_params, link_delete_params, link_update_params, link_list_objects_params + +__all__ = ["LinksResource", "AsyncLinksResource"] + + +class LinksResource(SyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def with_raw_response(self) -> LinksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return LinksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> LinksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return LinksResourceWithStreamingResponse(self) + + def retrieve( + self, + 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, + ) -> None: + """Retrieve one link: state, counts, and embedded active_run/last_run. + + Poll this + after POST /transfer. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + path_template("/connectors/v1/links/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def update( + self, + id: str, + *, + mode: Literal["once", "synced"] | Omit = omit, + policy: object | Omit = omit, + state: Literal["paused", "ready"] | 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, + ) -> None: + """ + Pause/resume a link (state "paused" | "ready"), change its mode (synced -> once + is the sync downgrade), or edit its policy in place. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + path_template("/connectors/v1/links/{id}", id=id), + body=maybe_transform( + { + "mode": mode, + "policy": policy, + "state": state, + }, + link_update_params.LinkUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def list( + self, + *, + connection_id: str | Omit = omit, + direction: Literal["import", "export"] | Omit = omit, + mode: Literal["once", "synced"] | Omit = omit, + pair_id: str | Omit = omit, + state: Literal["ready", "running", "active", "paused", "orphaned", "error"] | Omit = omit, + vault_id: 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, + ) -> None: + """ + List transfer links, filterable by vault, connection, direction, mode, and + state. + + 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._get( + "/connectors/v1/links", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "mode": mode, + "pair_id": pair_id, + "state": state, + "vault_id": vault_id, + }, + link_list_params.LinkListParams, + ), + ), + cast_to=NoneType, + ) + + def delete( + self, + id: str, + *, + vault_docs: Literal["keep", "delete"] | 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, + ) -> None: + """Delete a link and its ledger. + + vault_docs=delete additionally removes the vault + documents an import link brought in (default: keep). + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/connectors/v1/links/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"vault_docs": vault_docs}, link_delete_params.LinkDeleteParams), + ), + cast_to=NoneType, + ) + + def list_objects( + self, + id: str, + *, + cursor: str | Omit = omit, + state: Literal["pending", "transferring", "ingesting", "synced", "skipped", "failed", "tombstoned"] + | 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, + ) -> None: + """ + Per-file transfer ledger for a link: provider item, vault object, path, content + version, state, and error. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + path_template("/connectors/v1/links/{id}/objects", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor": cursor, + "state": state, + }, + link_list_objects_params.LinkListObjectsParams, + ), + ), + cast_to=NoneType, + ) + + +class AsyncLinksResource(AsyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def with_raw_response(self) -> AsyncLinksResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return AsyncLinksResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncLinksResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return AsyncLinksResourceWithStreamingResponse(self) + + async def retrieve( + self, + 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, + ) -> None: + """Retrieve one link: state, counts, and embedded active_run/last_run. + + Poll this + after POST /transfer. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + path_template("/connectors/v1/links/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def update( + self, + id: str, + *, + mode: Literal["once", "synced"] | Omit = omit, + policy: object | Omit = omit, + state: Literal["paused", "ready"] | 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, + ) -> None: + """ + Pause/resume a link (state "paused" | "ready"), change its mode (synced -> once + is the sync downgrade), or edit its policy in place. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + path_template("/connectors/v1/links/{id}", id=id), + body=await async_maybe_transform( + { + "mode": mode, + "policy": policy, + "state": state, + }, + link_update_params.LinkUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def list( + self, + *, + connection_id: str | Omit = omit, + direction: Literal["import", "export"] | Omit = omit, + mode: Literal["once", "synced"] | Omit = omit, + pair_id: str | Omit = omit, + state: Literal["ready", "running", "active", "paused", "orphaned", "error"] | Omit = omit, + vault_id: 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, + ) -> None: + """ + List transfer links, filterable by vault, connection, direction, mode, and + state. + + 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._get( + "/connectors/v1/links", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "mode": mode, + "pair_id": pair_id, + "state": state, + "vault_id": vault_id, + }, + link_list_params.LinkListParams, + ), + ), + cast_to=NoneType, + ) + + async def delete( + self, + id: str, + *, + vault_docs: Literal["keep", "delete"] | 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, + ) -> None: + """Delete a link and its ledger. + + vault_docs=delete additionally removes the vault + documents an import link brought in (default: keep). + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/connectors/v1/links/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"vault_docs": vault_docs}, link_delete_params.LinkDeleteParams), + ), + cast_to=NoneType, + ) + + async def list_objects( + self, + id: str, + *, + cursor: str | Omit = omit, + state: Literal["pending", "transferring", "ingesting", "synced", "skipped", "failed", "tombstoned"] + | 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, + ) -> None: + """ + Per-file transfer ledger for a link: provider item, vault object, path, content + version, state, and error. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + path_template("/connectors/v1/links/{id}/objects", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "cursor": cursor, + "state": state, + }, + link_list_objects_params.LinkListObjectsParams, + ), + ), + cast_to=NoneType, + ) + + +class LinksResourceWithRawResponse: + def __init__(self, links: LinksResource) -> None: + self._links = links + + self.retrieve = to_raw_response_wrapper( + links.retrieve, + ) + self.update = to_raw_response_wrapper( + links.update, + ) + self.list = to_raw_response_wrapper( + links.list, + ) + self.delete = to_raw_response_wrapper( + links.delete, + ) + self.list_objects = to_raw_response_wrapper( + links.list_objects, + ) + + +class AsyncLinksResourceWithRawResponse: + def __init__(self, links: AsyncLinksResource) -> None: + self._links = links + + self.retrieve = async_to_raw_response_wrapper( + links.retrieve, + ) + self.update = async_to_raw_response_wrapper( + links.update, + ) + self.list = async_to_raw_response_wrapper( + links.list, + ) + self.delete = async_to_raw_response_wrapper( + links.delete, + ) + self.list_objects = async_to_raw_response_wrapper( + links.list_objects, + ) + + +class LinksResourceWithStreamingResponse: + def __init__(self, links: LinksResource) -> None: + self._links = links + + self.retrieve = to_streamed_response_wrapper( + links.retrieve, + ) + self.update = to_streamed_response_wrapper( + links.update, + ) + self.list = to_streamed_response_wrapper( + links.list, + ) + self.delete = to_streamed_response_wrapper( + links.delete, + ) + self.list_objects = to_streamed_response_wrapper( + links.list_objects, + ) + + +class AsyncLinksResourceWithStreamingResponse: + def __init__(self, links: AsyncLinksResource) -> None: + self._links = links + + self.retrieve = async_to_streamed_response_wrapper( + links.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + links.update, + ) + self.list = async_to_streamed_response_wrapper( + links.list, + ) + self.delete = async_to_streamed_response_wrapper( + links.delete, + ) + self.list_objects = async_to_streamed_response_wrapper( + links.list_objects, + ) diff --git a/src/casedev/resources/connectors/v1/v1.py b/src/casedev/resources/connectors/v1/v1.py new file mode 100644 index 00000000..cff90974 --- /dev/null +++ b/src/casedev/resources/connectors/v1/v1.py @@ -0,0 +1,439 @@ +# 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 Literal + +import httpx + +from .links import ( + LinksResource, + AsyncLinksResource, + LinksResourceWithRawResponse, + AsyncLinksResourceWithRawResponse, + LinksResourceWithStreamingResponse, + AsyncLinksResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import maybe_transform, async_maybe_transform +from ...._compat import cached_property +from .connections import ( + ConnectionsResource, + AsyncConnectionsResource, + ConnectionsResourceWithRawResponse, + AsyncConnectionsResourceWithRawResponse, + ConnectionsResourceWithStreamingResponse, + AsyncConnectionsResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.connectors import v1_transfer_params, v1_sync_link_params +from .installations.installations import ( + InstallationsResource, + AsyncInstallationsResource, + InstallationsResourceWithRawResponse, + AsyncInstallationsResourceWithRawResponse, + InstallationsResourceWithStreamingResponse, + AsyncInstallationsResourceWithStreamingResponse, +) +from ....types.connectors.v1_transfer_response import V1TransferResponse +from ....types.connectors.v1_sync_link_response import V1SyncLinkResponse + +__all__ = ["V1Resource", "AsyncV1Resource"] + + +class V1Resource(SyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def installations(self) -> InstallationsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return InstallationsResource(self._client) + + @cached_property + def connections(self) -> ConnectionsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return ConnectionsResource(self._client) + + @cached_property + def links(self) -> LinksResource: + """Import and export between provider folders (Google Drive) and vaults""" + return LinksResource(self._client) + + @cached_property + def with_raw_response(self) -> V1ResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return V1ResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> V1ResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return V1ResourceWithStreamingResponse(self) + + def sync_link( + self, + *, + connection_id: str, + direction: Literal["import", "export"], + remote: v1_sync_link_params.Remote, + vault_id: str, + matter_id: Optional[str] | Omit = omit, + policy: v1_sync_link_params.Policy | 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, + ) -> V1SyncLinkResponse: + """ + Standing promise: backfill now, then stay current (the sync sweeper re-runs + synced links on a schedule). Same body as /transfer minus run_mode. Upserts the + link identified by (connection_id, direction, remote, vault_id); an existing + once-link is upgraded in place with its ledger and cursor preserved. Downgrade + or pause via PATCH /links/{id}. + + 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( + "/connectors/v1/sync-link", + body=maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "remote": remote, + "vault_id": vault_id, + "matter_id": matter_id, + "policy": policy, + }, + v1_sync_link_params.V1SyncLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1SyncLinkResponse, + ) + + def transfer( + self, + *, + connection_id: str, + direction: Literal["import", "export"], + remote: v1_transfer_params.Remote, + vault_id: str, + matter_id: Optional[str] | Omit = omit, + policy: v1_transfer_params.Policy | Omit = omit, + run_mode: Literal["auto", "full_reconcile"] | 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, + ) -> V1TransferResponse: + """ + One-shot import (provider folder → vault) or export (vault → provider folder). + Upserts the link identified by (connection_id, direction, remote, vault_id): + first call backfills, later calls move only new/changed files via the ledger. + Poll GET /links/{id} → active_run for progress. + + 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( + "/connectors/v1/transfer", + body=maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "remote": remote, + "vault_id": vault_id, + "matter_id": matter_id, + "policy": policy, + "run_mode": run_mode, + }, + v1_transfer_params.V1TransferParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1TransferResponse, + ) + + +class AsyncV1Resource(AsyncAPIResource): + """Import and export between provider folders (Google Drive) and vaults""" + + @cached_property + def installations(self) -> AsyncInstallationsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncInstallationsResource(self._client) + + @cached_property + def connections(self) -> AsyncConnectionsResource: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncConnectionsResource(self._client) + + @cached_property + def links(self) -> AsyncLinksResource: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncLinksResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return AsyncV1ResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return AsyncV1ResourceWithStreamingResponse(self) + + async def sync_link( + self, + *, + connection_id: str, + direction: Literal["import", "export"], + remote: v1_sync_link_params.Remote, + vault_id: str, + matter_id: Optional[str] | Omit = omit, + policy: v1_sync_link_params.Policy | 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, + ) -> V1SyncLinkResponse: + """ + Standing promise: backfill now, then stay current (the sync sweeper re-runs + synced links on a schedule). Same body as /transfer minus run_mode. Upserts the + link identified by (connection_id, direction, remote, vault_id); an existing + once-link is upgraded in place with its ledger and cursor preserved. Downgrade + or pause via PATCH /links/{id}. + + 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( + "/connectors/v1/sync-link", + body=await async_maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "remote": remote, + "vault_id": vault_id, + "matter_id": matter_id, + "policy": policy, + }, + v1_sync_link_params.V1SyncLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1SyncLinkResponse, + ) + + async def transfer( + self, + *, + connection_id: str, + direction: Literal["import", "export"], + remote: v1_transfer_params.Remote, + vault_id: str, + matter_id: Optional[str] | Omit = omit, + policy: v1_transfer_params.Policy | Omit = omit, + run_mode: Literal["auto", "full_reconcile"] | 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, + ) -> V1TransferResponse: + """ + One-shot import (provider folder → vault) or export (vault → provider folder). + Upserts the link identified by (connection_id, direction, remote, vault_id): + first call backfills, later calls move only new/changed files via the ledger. + Poll GET /links/{id} → active_run for progress. + + 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( + "/connectors/v1/transfer", + body=await async_maybe_transform( + { + "connection_id": connection_id, + "direction": direction, + "remote": remote, + "vault_id": vault_id, + "matter_id": matter_id, + "policy": policy, + "run_mode": run_mode, + }, + v1_transfer_params.V1TransferParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=V1TransferResponse, + ) + + +class V1ResourceWithRawResponse: + def __init__(self, v1: V1Resource) -> None: + self._v1 = v1 + + self.sync_link = to_raw_response_wrapper( + v1.sync_link, + ) + self.transfer = to_raw_response_wrapper( + v1.transfer, + ) + + @cached_property + def installations(self) -> InstallationsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return InstallationsResourceWithRawResponse(self._v1.installations) + + @cached_property + def connections(self) -> ConnectionsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return ConnectionsResourceWithRawResponse(self._v1.connections) + + @cached_property + def links(self) -> LinksResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return LinksResourceWithRawResponse(self._v1.links) + + +class AsyncV1ResourceWithRawResponse: + def __init__(self, v1: AsyncV1Resource) -> None: + self._v1 = v1 + + self.sync_link = async_to_raw_response_wrapper( + v1.sync_link, + ) + self.transfer = async_to_raw_response_wrapper( + v1.transfer, + ) + + @cached_property + def installations(self) -> AsyncInstallationsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncInstallationsResourceWithRawResponse(self._v1.installations) + + @cached_property + def connections(self) -> AsyncConnectionsResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncConnectionsResourceWithRawResponse(self._v1.connections) + + @cached_property + def links(self) -> AsyncLinksResourceWithRawResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncLinksResourceWithRawResponse(self._v1.links) + + +class V1ResourceWithStreamingResponse: + def __init__(self, v1: V1Resource) -> None: + self._v1 = v1 + + self.sync_link = to_streamed_response_wrapper( + v1.sync_link, + ) + self.transfer = to_streamed_response_wrapper( + v1.transfer, + ) + + @cached_property + def installations(self) -> InstallationsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return InstallationsResourceWithStreamingResponse(self._v1.installations) + + @cached_property + def connections(self) -> ConnectionsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return ConnectionsResourceWithStreamingResponse(self._v1.connections) + + @cached_property + def links(self) -> LinksResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return LinksResourceWithStreamingResponse(self._v1.links) + + +class AsyncV1ResourceWithStreamingResponse: + def __init__(self, v1: AsyncV1Resource) -> None: + self._v1 = v1 + + self.sync_link = async_to_streamed_response_wrapper( + v1.sync_link, + ) + self.transfer = async_to_streamed_response_wrapper( + v1.transfer, + ) + + @cached_property + def installations(self) -> AsyncInstallationsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncInstallationsResourceWithStreamingResponse(self._v1.installations) + + @cached_property + def connections(self) -> AsyncConnectionsResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncConnectionsResourceWithStreamingResponse(self._v1.connections) + + @cached_property + def links(self) -> AsyncLinksResourceWithStreamingResponse: + """Import and export between provider folders (Google Drive) and vaults""" + return AsyncLinksResourceWithStreamingResponse(self._v1.links) diff --git a/src/casedev/resources/database/database.py b/src/casedev/resources/database/database.py deleted file mode 100644 index 7c1f0e2f..00000000 --- a/src/casedev/resources/database/database.py +++ /dev/null @@ -1,108 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1.v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["DatabaseResource", "AsyncDatabaseResource"] - - -class DatabaseResource(SyncAPIResource): - @cached_property - def v1(self) -> V1Resource: - """Serverless PostgreSQL databases with instant branching""" - return V1Resource(self._client) - - @cached_property - def with_raw_response(self) -> DatabaseResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return DatabaseResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> DatabaseResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return DatabaseResourceWithStreamingResponse(self) - - -class AsyncDatabaseResource(AsyncAPIResource): - @cached_property - def v1(self) -> AsyncV1Resource: - """Serverless PostgreSQL databases with instant branching""" - return AsyncV1Resource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncDatabaseResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncDatabaseResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncDatabaseResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncDatabaseResourceWithStreamingResponse(self) - - -class DatabaseResourceWithRawResponse: - def __init__(self, database: DatabaseResource) -> None: - self._database = database - - @cached_property - def v1(self) -> V1ResourceWithRawResponse: - """Serverless PostgreSQL databases with instant branching""" - return V1ResourceWithRawResponse(self._database.v1) - - -class AsyncDatabaseResourceWithRawResponse: - def __init__(self, database: AsyncDatabaseResource) -> None: - self._database = database - - @cached_property - def v1(self) -> AsyncV1ResourceWithRawResponse: - """Serverless PostgreSQL databases with instant branching""" - return AsyncV1ResourceWithRawResponse(self._database.v1) - - -class DatabaseResourceWithStreamingResponse: - def __init__(self, database: DatabaseResource) -> None: - self._database = database - - @cached_property - def v1(self) -> V1ResourceWithStreamingResponse: - """Serverless PostgreSQL databases with instant branching""" - return V1ResourceWithStreamingResponse(self._database.v1) - - -class AsyncDatabaseResourceWithStreamingResponse: - def __init__(self, database: AsyncDatabaseResource) -> None: - self._database = database - - @cached_property - def v1(self) -> AsyncV1ResourceWithStreamingResponse: - """Serverless PostgreSQL databases with instant branching""" - return AsyncV1ResourceWithStreamingResponse(self._database.v1) diff --git a/src/casedev/resources/database/v1/__init__.py b/src/casedev/resources/database/v1/__init__.py deleted file mode 100644 index 56e28d44..00000000 --- a/src/casedev/resources/database/v1/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .projects import ( - ProjectsResource, - AsyncProjectsResource, - ProjectsResourceWithRawResponse, - AsyncProjectsResourceWithRawResponse, - ProjectsResourceWithStreamingResponse, - AsyncProjectsResourceWithStreamingResponse, -) - -__all__ = [ - "ProjectsResource", - "AsyncProjectsResource", - "ProjectsResourceWithRawResponse", - "AsyncProjectsResourceWithRawResponse", - "ProjectsResourceWithStreamingResponse", - "AsyncProjectsResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/database/v1/projects.py b/src/casedev/resources/database/v1/projects.py deleted file mode 100644 index 8b33fa40..00000000 --- a/src/casedev/resources/database/v1/projects.py +++ /dev/null @@ -1,775 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -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 ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.database.v1 import project_create_params, project_create_branch_params, project_get_connection_params -from ....types.database.v1.project_list_response import ProjectListResponse -from ....types.database.v1.project_create_response import ProjectCreateResponse -from ....types.database.v1.project_delete_response import ProjectDeleteResponse -from ....types.database.v1.project_retrieve_response import ProjectRetrieveResponse -from ....types.database.v1.project_create_branch_response import ProjectCreateBranchResponse -from ....types.database.v1.project_list_branches_response import ProjectListBranchesResponse -from ....types.database.v1.project_get_connection_response import ProjectGetConnectionResponse - -__all__ = ["ProjectsResource", "AsyncProjectsResource"] - - -class ProjectsResource(SyncAPIResource): - """Serverless PostgreSQL databases with instant branching""" - - @cached_property - def with_raw_response(self) -> ProjectsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return ProjectsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ProjectsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return ProjectsResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - description: str | Omit = omit, - region: Literal[ - "aws-us-east-1", - "aws-us-east-2", - "aws-us-west-2", - "aws-eu-central-1", - "aws-eu-west-1", - "aws-eu-west-2", - "aws-ap-southeast-1", - "aws-ap-southeast-2", - ] - | 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, - ) -> ProjectCreateResponse: - """Creates a new serverless Postgres database project powered by Neon. - - Includes - automatic scaling, connection pooling, and a default 'main' branch with 'neondb' - database. Supports branching for isolated dev/staging environments. Perfect for - case management applications, document workflows, and litigation support - systems. - - Args: - name: Project name (letters, numbers, hyphens, underscores only) - - description: Optional project description - - region: AWS region for database deployment - - 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( - "/database/v1/projects", - body=maybe_transform( - { - "name": name, - "description": description, - "region": region, - }, - project_create_params.ProjectCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectCreateResponse, - ) - - def retrieve( - self, - 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, - ) -> ProjectRetrieveResponse: - """ - Retrieves detailed information about a specific database project including - branches, databases, storage/compute metrics, connection host, and linked - deployments. Fetches live usage statistics from Neon API. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - path_template("/database/v1/projects/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectRetrieveResponse, - ) - - def list( - 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, - ) -> ProjectListResponse: - """ - Retrieves all serverless Postgres database projects for the authenticated - organization. Includes storage and compute metrics, plus linked application - deployments and Compute instances. - """ - return self._get( - "/database/v1/projects", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectListResponse, - ) - - def delete( - self, - 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, - ) -> ProjectDeleteResponse: - """ - Permanently deletes a database project from Neon and marks it as deleted in - Case.dev. This action cannot be undone and will destroy all data including - branches and databases. Use with caution. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - path_template("/database/v1/projects/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectDeleteResponse, - ) - - def create_branch( - self, - id: str, - *, - name: str, - parent_branch_id: 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, - ) -> ProjectCreateBranchResponse: - """Creates a new branch from the specified parent branch (or default 'main' - branch). - - Branches provide instant point-in-time clones of your database for - isolated development, staging, testing, or feature work. Perfect for testing - schema changes, running migrations safely, or creating ephemeral preview - environments. - - Args: - name: Branch name (letters, numbers, hyphens, underscores only) - - parent_branch_id: Parent branch ID to clone from (defaults to main branch) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - path_template("/database/v1/projects/{id}/branches", id=id), - body=maybe_transform( - { - "name": name, - "parent_branch_id": parent_branch_id, - }, - project_create_branch_params.ProjectCreateBranchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectCreateBranchResponse, - ) - - def get_connection( - self, - id: str, - *, - branch: str | Omit = omit, - pooled: bool | 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, - ) -> ProjectGetConnectionResponse: - """Retrieves the PostgreSQL connection URI for a database project. - - Supports - selecting specific branches and pooled vs direct connections. Connection strings - include credentials and should be stored securely. Use for configuring - applications and deployment environments. - - Args: - branch: Branch name (defaults to 'main') - - pooled: Use pooled connection (PgBouncer) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - path_template("/database/v1/projects/{id}/connection", id=id), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "branch": branch, - "pooled": pooled, - }, - project_get_connection_params.ProjectGetConnectionParams, - ), - ), - cast_to=ProjectGetConnectionResponse, - ) - - def list_branches( - self, - 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, - ) -> ProjectListBranchesResponse: - """Retrieves all branches for a database project. - - Branches enable isolated - development and testing environments with instant point-in-time cloning. Each - branch includes the default branch and any custom branches created for staging, - testing, or feature development. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - path_template("/database/v1/projects/{id}/branches", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectListBranchesResponse, - ) - - -class AsyncProjectsResource(AsyncAPIResource): - """Serverless PostgreSQL databases with instant branching""" - - @cached_property - def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncProjectsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncProjectsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncProjectsResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - description: str | Omit = omit, - region: Literal[ - "aws-us-east-1", - "aws-us-east-2", - "aws-us-west-2", - "aws-eu-central-1", - "aws-eu-west-1", - "aws-eu-west-2", - "aws-ap-southeast-1", - "aws-ap-southeast-2", - ] - | 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, - ) -> ProjectCreateResponse: - """Creates a new serverless Postgres database project powered by Neon. - - Includes - automatic scaling, connection pooling, and a default 'main' branch with 'neondb' - database. Supports branching for isolated dev/staging environments. Perfect for - case management applications, document workflows, and litigation support - systems. - - Args: - name: Project name (letters, numbers, hyphens, underscores only) - - description: Optional project description - - region: AWS region for database deployment - - 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( - "/database/v1/projects", - body=await async_maybe_transform( - { - "name": name, - "description": description, - "region": region, - }, - project_create_params.ProjectCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectCreateResponse, - ) - - async def retrieve( - self, - 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, - ) -> ProjectRetrieveResponse: - """ - Retrieves detailed information about a specific database project including - branches, databases, storage/compute metrics, connection host, and linked - deployments. Fetches live usage statistics from Neon API. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - path_template("/database/v1/projects/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectRetrieveResponse, - ) - - async def list( - 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, - ) -> ProjectListResponse: - """ - Retrieves all serverless Postgres database projects for the authenticated - organization. Includes storage and compute metrics, plus linked application - deployments and Compute instances. - """ - return await self._get( - "/database/v1/projects", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectListResponse, - ) - - async def delete( - self, - 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, - ) -> ProjectDeleteResponse: - """ - Permanently deletes a database project from Neon and marks it as deleted in - Case.dev. This action cannot be undone and will destroy all data including - branches and databases. Use with caution. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - path_template("/database/v1/projects/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectDeleteResponse, - ) - - async def create_branch( - self, - id: str, - *, - name: str, - parent_branch_id: 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, - ) -> ProjectCreateBranchResponse: - """Creates a new branch from the specified parent branch (or default 'main' - branch). - - Branches provide instant point-in-time clones of your database for - isolated development, staging, testing, or feature work. Perfect for testing - schema changes, running migrations safely, or creating ephemeral preview - environments. - - Args: - name: Branch name (letters, numbers, hyphens, underscores only) - - parent_branch_id: Parent branch ID to clone from (defaults to main branch) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - path_template("/database/v1/projects/{id}/branches", id=id), - body=await async_maybe_transform( - { - "name": name, - "parent_branch_id": parent_branch_id, - }, - project_create_branch_params.ProjectCreateBranchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectCreateBranchResponse, - ) - - async def get_connection( - self, - id: str, - *, - branch: str | Omit = omit, - pooled: bool | 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, - ) -> ProjectGetConnectionResponse: - """Retrieves the PostgreSQL connection URI for a database project. - - Supports - selecting specific branches and pooled vs direct connections. Connection strings - include credentials and should be stored securely. Use for configuring - applications and deployment environments. - - Args: - branch: Branch name (defaults to 'main') - - pooled: Use pooled connection (PgBouncer) - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - path_template("/database/v1/projects/{id}/connection", id=id), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "branch": branch, - "pooled": pooled, - }, - project_get_connection_params.ProjectGetConnectionParams, - ), - ), - cast_to=ProjectGetConnectionResponse, - ) - - async def list_branches( - self, - 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, - ) -> ProjectListBranchesResponse: - """Retrieves all branches for a database project. - - Branches enable isolated - development and testing environments with instant point-in-time cloning. Each - branch includes the default branch and any custom branches created for staging, - testing, or feature development. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - path_template("/database/v1/projects/{id}/branches", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProjectListBranchesResponse, - ) - - -class ProjectsResourceWithRawResponse: - def __init__(self, projects: ProjectsResource) -> None: - self._projects = projects - - self.create = to_raw_response_wrapper( - projects.create, - ) - self.retrieve = to_raw_response_wrapper( - projects.retrieve, - ) - self.list = to_raw_response_wrapper( - projects.list, - ) - self.delete = to_raw_response_wrapper( - projects.delete, - ) - self.create_branch = to_raw_response_wrapper( - projects.create_branch, - ) - self.get_connection = to_raw_response_wrapper( - projects.get_connection, - ) - self.list_branches = to_raw_response_wrapper( - projects.list_branches, - ) - - -class AsyncProjectsResourceWithRawResponse: - def __init__(self, projects: AsyncProjectsResource) -> None: - self._projects = projects - - self.create = async_to_raw_response_wrapper( - projects.create, - ) - self.retrieve = async_to_raw_response_wrapper( - projects.retrieve, - ) - self.list = async_to_raw_response_wrapper( - projects.list, - ) - self.delete = async_to_raw_response_wrapper( - projects.delete, - ) - self.create_branch = async_to_raw_response_wrapper( - projects.create_branch, - ) - self.get_connection = async_to_raw_response_wrapper( - projects.get_connection, - ) - self.list_branches = async_to_raw_response_wrapper( - projects.list_branches, - ) - - -class ProjectsResourceWithStreamingResponse: - def __init__(self, projects: ProjectsResource) -> None: - self._projects = projects - - self.create = to_streamed_response_wrapper( - projects.create, - ) - self.retrieve = to_streamed_response_wrapper( - projects.retrieve, - ) - self.list = to_streamed_response_wrapper( - projects.list, - ) - self.delete = to_streamed_response_wrapper( - projects.delete, - ) - self.create_branch = to_streamed_response_wrapper( - projects.create_branch, - ) - self.get_connection = to_streamed_response_wrapper( - projects.get_connection, - ) - self.list_branches = to_streamed_response_wrapper( - projects.list_branches, - ) - - -class AsyncProjectsResourceWithStreamingResponse: - def __init__(self, projects: AsyncProjectsResource) -> None: - self._projects = projects - - self.create = async_to_streamed_response_wrapper( - projects.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - projects.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - projects.list, - ) - self.delete = async_to_streamed_response_wrapper( - projects.delete, - ) - self.create_branch = async_to_streamed_response_wrapper( - projects.create_branch, - ) - self.get_connection = async_to_streamed_response_wrapper( - projects.get_connection, - ) - self.list_branches = async_to_streamed_response_wrapper( - projects.list_branches, - ) diff --git a/src/casedev/resources/database/v1/v1.py b/src/casedev/resources/database/v1/v1.py deleted file mode 100644 index 85259d30..00000000 --- a/src/casedev/resources/database/v1/v1.py +++ /dev/null @@ -1,185 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .projects import ( - ProjectsResource, - AsyncProjectsResource, - ProjectsResourceWithRawResponse, - AsyncProjectsResourceWithRawResponse, - ProjectsResourceWithStreamingResponse, - AsyncProjectsResourceWithStreamingResponse, -) -from ...._types import Body, Query, Headers, NotGiven, not_given -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.database.v1_get_usage_response import V1GetUsageResponse - -__all__ = ["V1Resource", "AsyncV1Resource"] - - -class V1Resource(SyncAPIResource): - """Serverless PostgreSQL databases with instant branching""" - - @cached_property - def projects(self) -> ProjectsResource: - """Serverless PostgreSQL databases with instant branching""" - return ProjectsResource(self._client) - - @cached_property - def with_raw_response(self) -> V1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return V1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return V1ResourceWithStreamingResponse(self) - - def get_usage( - 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, - ) -> V1GetUsageResponse: - """ - Returns detailed database usage statistics and billing information for the - current billing period. Includes compute hours, storage, data transfer, and - branch counts with associated costs broken down by project. - """ - return self._get( - "/database/v1/usage", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1GetUsageResponse, - ) - - -class AsyncV1Resource(AsyncAPIResource): - """Serverless PostgreSQL databases with instant branching""" - - @cached_property - def projects(self) -> AsyncProjectsResource: - """Serverless PostgreSQL databases with instant branching""" - return AsyncProjectsResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncV1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncV1ResourceWithStreamingResponse(self) - - async def get_usage( - 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, - ) -> V1GetUsageResponse: - """ - Returns detailed database usage statistics and billing information for the - current billing period. Includes compute hours, storage, data transfer, and - branch counts with associated costs broken down by project. - """ - return await self._get( - "/database/v1/usage", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1GetUsageResponse, - ) - - -class V1ResourceWithRawResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.get_usage = to_raw_response_wrapper( - v1.get_usage, - ) - - @cached_property - def projects(self) -> ProjectsResourceWithRawResponse: - """Serverless PostgreSQL databases with instant branching""" - return ProjectsResourceWithRawResponse(self._v1.projects) - - -class AsyncV1ResourceWithRawResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.get_usage = async_to_raw_response_wrapper( - v1.get_usage, - ) - - @cached_property - def projects(self) -> AsyncProjectsResourceWithRawResponse: - """Serverless PostgreSQL databases with instant branching""" - return AsyncProjectsResourceWithRawResponse(self._v1.projects) - - -class V1ResourceWithStreamingResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.get_usage = to_streamed_response_wrapper( - v1.get_usage, - ) - - @cached_property - def projects(self) -> ProjectsResourceWithStreamingResponse: - """Serverless PostgreSQL databases with instant branching""" - return ProjectsResourceWithStreamingResponse(self._v1.projects) - - -class AsyncV1ResourceWithStreamingResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.get_usage = async_to_streamed_response_wrapper( - v1.get_usage, - ) - - @cached_property - def projects(self) -> AsyncProjectsResourceWithStreamingResponse: - """Serverless PostgreSQL databases with instant branching""" - return AsyncProjectsResourceWithStreamingResponse(self._v1.projects) diff --git a/src/casedev/resources/format/__init__.py b/src/casedev/resources/format/__init__.py deleted file mode 100644 index c3ff26ae..00000000 --- a/src/casedev/resources/format/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .format import ( - FormatResource, - AsyncFormatResource, - FormatResourceWithRawResponse, - AsyncFormatResourceWithRawResponse, - FormatResourceWithStreamingResponse, - AsyncFormatResourceWithStreamingResponse, -) - -__all__ = [ - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", - "FormatResource", - "AsyncFormatResource", - "FormatResourceWithRawResponse", - "AsyncFormatResourceWithRawResponse", - "FormatResourceWithStreamingResponse", - "AsyncFormatResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/format/format.py b/src/casedev/resources/format/format.py deleted file mode 100644 index e3c7ea24..00000000 --- a/src/casedev/resources/format/format.py +++ /dev/null @@ -1,108 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1.v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["FormatResource", "AsyncFormatResource"] - - -class FormatResource(SyncAPIResource): - @cached_property - def v1(self) -> V1Resource: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return V1Resource(self._client) - - @cached_property - def with_raw_response(self) -> FormatResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return FormatResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FormatResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return FormatResourceWithStreamingResponse(self) - - -class AsyncFormatResource(AsyncAPIResource): - @cached_property - def v1(self) -> AsyncV1Resource: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncV1Resource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncFormatResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncFormatResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFormatResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncFormatResourceWithStreamingResponse(self) - - -class FormatResourceWithRawResponse: - def __init__(self, format: FormatResource) -> None: - self._format = format - - @cached_property - def v1(self) -> V1ResourceWithRawResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return V1ResourceWithRawResponse(self._format.v1) - - -class AsyncFormatResourceWithRawResponse: - def __init__(self, format: AsyncFormatResource) -> None: - self._format = format - - @cached_property - def v1(self) -> AsyncV1ResourceWithRawResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncV1ResourceWithRawResponse(self._format.v1) - - -class FormatResourceWithStreamingResponse: - def __init__(self, format: FormatResource) -> None: - self._format = format - - @cached_property - def v1(self) -> V1ResourceWithStreamingResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return V1ResourceWithStreamingResponse(self._format.v1) - - -class AsyncFormatResourceWithStreamingResponse: - def __init__(self, format: AsyncFormatResource) -> None: - self._format = format - - @cached_property - def v1(self) -> AsyncV1ResourceWithStreamingResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncV1ResourceWithStreamingResponse(self._format.v1) diff --git a/src/casedev/resources/format/v1/__init__.py b/src/casedev/resources/format/v1/__init__.py deleted file mode 100644 index 368db88d..00000000 --- a/src/casedev/resources/format/v1/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .templates import ( - TemplatesResource, - AsyncTemplatesResource, - TemplatesResourceWithRawResponse, - AsyncTemplatesResourceWithRawResponse, - TemplatesResourceWithStreamingResponse, - AsyncTemplatesResourceWithStreamingResponse, -) - -__all__ = [ - "TemplatesResource", - "AsyncTemplatesResource", - "TemplatesResourceWithRawResponse", - "AsyncTemplatesResourceWithRawResponse", - "TemplatesResourceWithStreamingResponse", - "AsyncTemplatesResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/format/v1/templates.py b/src/casedev/resources/format/v1/templates.py deleted file mode 100644 index 09364955..00000000 --- a/src/casedev/resources/format/v1/templates.py +++ /dev/null @@ -1,421 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -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 ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.format.v1 import template_list_params, template_create_params -from ....types.format.v1.template_list_response import TemplateListResponse -from ....types.format.v1.template_create_response import TemplateCreateResponse -from ....types.format.v1.template_retrieve_response import TemplateRetrieveResponse - -__all__ = ["TemplatesResource", "AsyncTemplatesResource"] - - -class TemplatesResource(SyncAPIResource): - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - - @cached_property - def with_raw_response(self) -> TemplatesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return TemplatesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TemplatesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return TemplatesResourceWithStreamingResponse(self) - - def create( - self, - *, - content: str, - name: str, - type: Literal["caption", "signature", "letterhead", "certificate", "footer", "custom"], - description: str | Omit = omit, - styles: object | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - variables: 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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TemplateCreateResponse: - """Create a new format template for document formatting. - - Templates support - variables using `{{variable}}` syntax and can be used for captions, signatures, - letterheads, certificates, footers, or custom formatting needs. - - Args: - content: Template content with {{variable}} placeholders - - name: Template name - - type: Template type - - description: Template description - - styles: CSS styles for the template - - tags: Template tags for organization - - variables: Template variables (auto-detected if not provided) - - 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( - "/format/v1/templates", - body=maybe_transform( - { - "content": content, - "name": name, - "type": type, - "description": description, - "styles": styles, - "tags": tags, - "variables": variables, - }, - template_create_params.TemplateCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TemplateCreateResponse, - ) - - def retrieve( - self, - 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, - ) -> TemplateRetrieveResponse: - """Retrieve a specific document format template by ID. - - Format templates define how - documents should be structured and formatted for specific legal use cases such - as contracts, briefs, or pleadings. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - path_template("/format/v1/templates/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TemplateRetrieveResponse, - ) - - def list( - self, - *, - type: 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, - ) -> TemplateListResponse: - """Retrieve all format templates for the organization. - - Templates define reusable - document formatting patterns with customizable variables for consistent legal - document generation. - - Filter by type to get specific template categories like contracts, pleadings, or - correspondence. - - Args: - type: Filter templates by type (e.g., contract, pleading, letter) - - 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( - "/format/v1/templates", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"type": type}, template_list_params.TemplateListParams), - ), - cast_to=TemplateListResponse, - ) - - -class AsyncTemplatesResource(AsyncAPIResource): - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - - @cached_property - def with_raw_response(self) -> AsyncTemplatesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncTemplatesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTemplatesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncTemplatesResourceWithStreamingResponse(self) - - async def create( - self, - *, - content: str, - name: str, - type: Literal["caption", "signature", "letterhead", "certificate", "footer", "custom"], - description: str | Omit = omit, - styles: object | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - variables: 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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TemplateCreateResponse: - """Create a new format template for document formatting. - - Templates support - variables using `{{variable}}` syntax and can be used for captions, signatures, - letterheads, certificates, footers, or custom formatting needs. - - Args: - content: Template content with {{variable}} placeholders - - name: Template name - - type: Template type - - description: Template description - - styles: CSS styles for the template - - tags: Template tags for organization - - variables: Template variables (auto-detected if not provided) - - 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( - "/format/v1/templates", - body=await async_maybe_transform( - { - "content": content, - "name": name, - "type": type, - "description": description, - "styles": styles, - "tags": tags, - "variables": variables, - }, - template_create_params.TemplateCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TemplateCreateResponse, - ) - - async def retrieve( - self, - 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, - ) -> TemplateRetrieveResponse: - """Retrieve a specific document format template by ID. - - Format templates define how - documents should be structured and formatted for specific legal use cases such - as contracts, briefs, or pleadings. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - path_template("/format/v1/templates/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TemplateRetrieveResponse, - ) - - async def list( - self, - *, - type: 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, - ) -> TemplateListResponse: - """Retrieve all format templates for the organization. - - Templates define reusable - document formatting patterns with customizable variables for consistent legal - document generation. - - Filter by type to get specific template categories like contracts, pleadings, or - correspondence. - - Args: - type: Filter templates by type (e.g., contract, pleading, letter) - - 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( - "/format/v1/templates", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"type": type}, template_list_params.TemplateListParams), - ), - cast_to=TemplateListResponse, - ) - - -class TemplatesResourceWithRawResponse: - def __init__(self, templates: TemplatesResource) -> None: - self._templates = templates - - self.create = to_raw_response_wrapper( - templates.create, - ) - self.retrieve = to_raw_response_wrapper( - templates.retrieve, - ) - self.list = to_raw_response_wrapper( - templates.list, - ) - - -class AsyncTemplatesResourceWithRawResponse: - def __init__(self, templates: AsyncTemplatesResource) -> None: - self._templates = templates - - self.create = async_to_raw_response_wrapper( - templates.create, - ) - self.retrieve = async_to_raw_response_wrapper( - templates.retrieve, - ) - self.list = async_to_raw_response_wrapper( - templates.list, - ) - - -class TemplatesResourceWithStreamingResponse: - def __init__(self, templates: TemplatesResource) -> None: - self._templates = templates - - self.create = to_streamed_response_wrapper( - templates.create, - ) - self.retrieve = to_streamed_response_wrapper( - templates.retrieve, - ) - self.list = to_streamed_response_wrapper( - templates.list, - ) - - -class AsyncTemplatesResourceWithStreamingResponse: - def __init__(self, templates: AsyncTemplatesResource) -> None: - self._templates = templates - - self.create = async_to_streamed_response_wrapper( - templates.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - templates.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - templates.list, - ) diff --git a/src/casedev/resources/format/v1/v1.py b/src/casedev/resources/format/v1/v1.py deleted file mode 100644 index 166fe1ce..00000000 --- a/src/casedev/resources/format/v1/v1.py +++ /dev/null @@ -1,260 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from .templates import ( - TemplatesResource, - AsyncTemplatesResource, - TemplatesResourceWithRawResponse, - AsyncTemplatesResourceWithRawResponse, - TemplatesResourceWithStreamingResponse, - AsyncTemplatesResourceWithStreamingResponse, -) -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_custom_raw_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.format import v1_create_document_params - -__all__ = ["V1Resource", "AsyncV1Resource"] - - -class V1Resource(SyncAPIResource): - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - - @cached_property - def templates(self) -> TemplatesResource: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return TemplatesResource(self._client) - - @cached_property - def with_raw_response(self) -> V1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return V1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return V1ResourceWithStreamingResponse(self) - - def create_document( - self, - *, - content: str, - output_format: Literal["pdf", "docx", "html_preview"], - input_format: Literal["md", "json", "text"] | Omit = omit, - options: v1_create_document_params.Options | 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: - """ - Convert Markdown, JSON, or text content to professionally formatted PDF, DOCX, - or HTML documents. Supports template components with variable interpolation for - creating consistent legal documents like contracts, briefs, and reports. - - Args: - content: The source content to format - - output_format: Desired output format - - input_format: Format of the input content - - options: Optional template composition and styling settings used during document - generation - - 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": "application/pdf", **(extra_headers or {})} - return self._post( - "/format/v1/document", - body=maybe_transform( - { - "content": content, - "output_format": output_format, - "input_format": input_format, - "options": options, - }, - v1_create_document_params.V1CreateDocumentParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BinaryAPIResponse, - ) - - -class AsyncV1Resource(AsyncAPIResource): - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - - @cached_property - def templates(self) -> AsyncTemplatesResource: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncTemplatesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncV1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncV1ResourceWithStreamingResponse(self) - - async def create_document( - self, - *, - content: str, - output_format: Literal["pdf", "docx", "html_preview"], - input_format: Literal["md", "json", "text"] | Omit = omit, - options: v1_create_document_params.Options | 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: - """ - Convert Markdown, JSON, or text content to professionally formatted PDF, DOCX, - or HTML documents. Supports template components with variable interpolation for - creating consistent legal documents like contracts, briefs, and reports. - - Args: - content: The source content to format - - output_format: Desired output format - - input_format: Format of the input content - - options: Optional template composition and styling settings used during document - generation - - 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": "application/pdf", **(extra_headers or {})} - return await self._post( - "/format/v1/document", - body=await async_maybe_transform( - { - "content": content, - "output_format": output_format, - "input_format": input_format, - "options": options, - }, - v1_create_document_params.V1CreateDocumentParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AsyncBinaryAPIResponse, - ) - - -class V1ResourceWithRawResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.create_document = to_custom_raw_response_wrapper( - v1.create_document, - BinaryAPIResponse, - ) - - @cached_property - def templates(self) -> TemplatesResourceWithRawResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return TemplatesResourceWithRawResponse(self._v1.templates) - - -class AsyncV1ResourceWithRawResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.create_document = async_to_custom_raw_response_wrapper( - v1.create_document, - AsyncBinaryAPIResponse, - ) - - @cached_property - def templates(self) -> AsyncTemplatesResourceWithRawResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncTemplatesResourceWithRawResponse(self._v1.templates) - - -class V1ResourceWithStreamingResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.create_document = to_custom_streamed_response_wrapper( - v1.create_document, - StreamedBinaryAPIResponse, - ) - - @cached_property - def templates(self) -> TemplatesResourceWithStreamingResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return TemplatesResourceWithStreamingResponse(self._v1.templates) - - -class AsyncV1ResourceWithStreamingResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.create_document = async_to_custom_streamed_response_wrapper( - v1.create_document, - AsyncStreamedBinaryAPIResponse, - ) - - @cached_property - def templates(self) -> AsyncTemplatesResourceWithStreamingResponse: - """Document formatting and template rendering (MD/JSON to PDF/DOCX)""" - return AsyncTemplatesResourceWithStreamingResponse(self._v1.templates) diff --git a/src/casedev/resources/legal/v1.py b/src/casedev/resources/legal/v1.py index 92f34cc6..6775550c 100644 --- a/src/casedev/resources/legal/v1.py +++ b/src/casedev/resources/legal/v1.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union, Optional +from typing import Union from datetime import date from typing_extensions import Literal @@ -20,7 +20,6 @@ ) from ...types.legal import ( v1_find_params, - v1_draft_params, v1_docket_params, v1_verify_params, v1_similar_params, @@ -36,7 +35,6 @@ ) from ..._base_client import make_request_options from ...types.legal.v1_find_response import V1FindResponse -from ...types.legal.v1_draft_response import V1DraftResponse from ...types.legal.v1_docket_response import V1DocketResponse from ...types.legal.v1_verify_response import V1VerifyResponse from ...types.legal.v1_similar_response import V1SimilarResponse @@ -124,7 +122,8 @@ def docket( acknowledgePacerFees: true. PACER charges up to $3.00 per docket sheet plus a $0.05 service fee. Only valid with type: "lookup". - offset: Offset for search results or entry list + offset: Offset for search results or entry list (maximum 200 when including lookup + entries) query: Case name or party name search query (required for search) @@ -160,87 +159,6 @@ def docket( cast_to=V1DocketResponse, ) - def draft( - self, - *, - instructions: str, - vault_id: str, - citations: bool | Omit = omit, - format: Optional[str] | Omit = omit, - length: Optional[v1_draft_params.Length] | Omit = omit, - model: Optional[str] | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, - output_name: Optional[str] | Omit = omit, - output_type: Literal["pdf", "docx", "xlsx", "pptx", "md"] | Omit = omit, - verified: bool | 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, - ) -> V1DraftResponse: - """Generate a legal document with structured inputs. - - Powered by an agent that - handles research, formatting, citation verification, and vault upload. Returns a - run ID for polling. - - Args: - instructions: What to draft — the core task. E.g., "Motion to compel defendant to produce - discovery responses" - - vault_id: Vault ID where the final document will be uploaded - - citations: Research and include legal citations - - format: Court or jurisdiction formatting hint. Triggers a legal-skills search. E.g., - "California Superior Court", "SDNY", "federal pleading" - - length: Target document length - - model: LLM model override. Defaults to anthropic/claude-sonnet-4.6 - - object_ids: Vault object IDs to use as source/reference documents - - output_name: Filename for the output document. Auto-generated if omitted. - - output_type: Output file format - - verified: Verify all citations in a loop — re-run verification and repair bad citations - until they pass - - 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( - "/legal/v1/draft", - body=maybe_transform( - { - "instructions": instructions, - "vault_id": vault_id, - "citations": citations, - "format": format, - "length": length, - "model": model, - "object_ids": object_ids, - "output_name": output_name, - "output_type": output_type, - "verified": verified, - }, - v1_draft_params.V1DraftParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1DraftResponse, - ) - def find( self, *, @@ -948,7 +866,8 @@ async def docket( acknowledgePacerFees: true. PACER charges up to $3.00 per docket sheet plus a $0.05 service fee. Only valid with type: "lookup". - offset: Offset for search results or entry list + offset: Offset for search results or entry list (maximum 200 when including lookup + entries) query: Case name or party name search query (required for search) @@ -984,87 +903,6 @@ async def docket( cast_to=V1DocketResponse, ) - async def draft( - self, - *, - instructions: str, - vault_id: str, - citations: bool | Omit = omit, - format: Optional[str] | Omit = omit, - length: Optional[v1_draft_params.Length] | Omit = omit, - model: Optional[str] | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, - output_name: Optional[str] | Omit = omit, - output_type: Literal["pdf", "docx", "xlsx", "pptx", "md"] | Omit = omit, - verified: bool | 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, - ) -> V1DraftResponse: - """Generate a legal document with structured inputs. - - Powered by an agent that - handles research, formatting, citation verification, and vault upload. Returns a - run ID for polling. - - Args: - instructions: What to draft — the core task. E.g., "Motion to compel defendant to produce - discovery responses" - - vault_id: Vault ID where the final document will be uploaded - - citations: Research and include legal citations - - format: Court or jurisdiction formatting hint. Triggers a legal-skills search. E.g., - "California Superior Court", "SDNY", "federal pleading" - - length: Target document length - - model: LLM model override. Defaults to anthropic/claude-sonnet-4.6 - - object_ids: Vault object IDs to use as source/reference documents - - output_name: Filename for the output document. Auto-generated if omitted. - - output_type: Output file format - - verified: Verify all citations in a loop — re-run verification and repair bad citations - until they pass - - 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( - "/legal/v1/draft", - body=await async_maybe_transform( - { - "instructions": instructions, - "vault_id": vault_id, - "citations": citations, - "format": format, - "length": length, - "model": model, - "object_ids": object_ids, - "output_name": output_name, - "output_type": output_type, - "verified": verified, - }, - v1_draft_params.V1DraftParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1DraftResponse, - ) - async def find( self, *, @@ -1710,9 +1548,6 @@ def __init__(self, v1: V1Resource) -> None: self.docket = to_raw_response_wrapper( v1.docket, ) - self.draft = to_raw_response_wrapper( - v1.draft, - ) self.find = to_raw_response_wrapper( v1.find, ) @@ -1758,9 +1593,6 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.docket = async_to_raw_response_wrapper( v1.docket, ) - self.draft = async_to_raw_response_wrapper( - v1.draft, - ) self.find = async_to_raw_response_wrapper( v1.find, ) @@ -1806,9 +1638,6 @@ def __init__(self, v1: V1Resource) -> None: self.docket = to_streamed_response_wrapper( v1.docket, ) - self.draft = to_streamed_response_wrapper( - v1.draft, - ) self.find = to_streamed_response_wrapper( v1.find, ) @@ -1854,9 +1683,6 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.docket = async_to_streamed_response_wrapper( v1.docket, ) - self.draft = async_to_streamed_response_wrapper( - v1.draft, - ) self.find = async_to_streamed_response_wrapper( v1.find, ) diff --git a/src/casedev/resources/mail/__init__.py b/src/casedev/resources/linc/__init__.py similarity index 54% rename from src/casedev/resources/mail/__init__.py rename to src/casedev/resources/linc/__init__.py index 35f6ebf0..71fe8770 100644 --- a/src/casedev/resources/mail/__init__.py +++ b/src/casedev/resources/linc/__init__.py @@ -8,13 +8,13 @@ V1ResourceWithStreamingResponse, AsyncV1ResourceWithStreamingResponse, ) -from .mail import ( - MailResource, - AsyncMailResource, - MailResourceWithRawResponse, - AsyncMailResourceWithRawResponse, - MailResourceWithStreamingResponse, - AsyncMailResourceWithStreamingResponse, +from .linc import ( + LincResource, + AsyncLincResource, + LincResourceWithRawResponse, + AsyncLincResourceWithRawResponse, + LincResourceWithStreamingResponse, + AsyncLincResourceWithStreamingResponse, ) __all__ = [ @@ -24,10 +24,10 @@ "AsyncV1ResourceWithRawResponse", "V1ResourceWithStreamingResponse", "AsyncV1ResourceWithStreamingResponse", - "MailResource", - "AsyncMailResource", - "MailResourceWithRawResponse", - "AsyncMailResourceWithRawResponse", - "MailResourceWithStreamingResponse", - "AsyncMailResourceWithStreamingResponse", + "LincResource", + "AsyncLincResource", + "LincResourceWithRawResponse", + "AsyncLincResourceWithRawResponse", + "LincResourceWithStreamingResponse", + "AsyncLincResourceWithStreamingResponse", ] diff --git a/src/casedev/resources/mail/mail.py b/src/casedev/resources/linc/linc.py similarity index 61% rename from src/casedev/resources/mail/mail.py rename to src/casedev/resources/linc/linc.py index c97214b9..3eedd0b7 100644 --- a/src/casedev/resources/mail/mail.py +++ b/src/casedev/resources/linc/linc.py @@ -13,90 +13,90 @@ from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -__all__ = ["MailResource", "AsyncMailResource"] +__all__ = ["LincResource", "AsyncLincResource"] -class MailResource(SyncAPIResource): +class LincResource(SyncAPIResource): @cached_property def v1(self) -> V1Resource: return V1Resource(self._client) @cached_property - def with_raw_response(self) -> MailResourceWithRawResponse: + def with_raw_response(self) -> LincResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return MailResourceWithRawResponse(self) + return LincResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> MailResourceWithStreamingResponse: + def with_streaming_response(self) -> LincResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return MailResourceWithStreamingResponse(self) + return LincResourceWithStreamingResponse(self) -class AsyncMailResource(AsyncAPIResource): +class AsyncLincResource(AsyncAPIResource): @cached_property def v1(self) -> AsyncV1Resource: return AsyncV1Resource(self._client) @cached_property - def with_raw_response(self) -> AsyncMailResourceWithRawResponse: + def with_raw_response(self) -> AsyncLincResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AsyncMailResourceWithRawResponse(self) + return AsyncLincResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncMailResourceWithStreamingResponse: + def with_streaming_response(self) -> AsyncLincResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AsyncMailResourceWithStreamingResponse(self) + return AsyncLincResourceWithStreamingResponse(self) -class MailResourceWithRawResponse: - def __init__(self, mail: MailResource) -> None: - self._mail = mail +class LincResourceWithRawResponse: + def __init__(self, linc: LincResource) -> None: + self._linc = linc @cached_property def v1(self) -> V1ResourceWithRawResponse: - return V1ResourceWithRawResponse(self._mail.v1) + return V1ResourceWithRawResponse(self._linc.v1) -class AsyncMailResourceWithRawResponse: - def __init__(self, mail: AsyncMailResource) -> None: - self._mail = mail +class AsyncLincResourceWithRawResponse: + def __init__(self, linc: AsyncLincResource) -> None: + self._linc = linc @cached_property def v1(self) -> AsyncV1ResourceWithRawResponse: - return AsyncV1ResourceWithRawResponse(self._mail.v1) + return AsyncV1ResourceWithRawResponse(self._linc.v1) -class MailResourceWithStreamingResponse: - def __init__(self, mail: MailResource) -> None: - self._mail = mail +class LincResourceWithStreamingResponse: + def __init__(self, linc: LincResource) -> None: + self._linc = linc @cached_property def v1(self) -> V1ResourceWithStreamingResponse: - return V1ResourceWithStreamingResponse(self._mail.v1) + return V1ResourceWithStreamingResponse(self._linc.v1) -class AsyncMailResourceWithStreamingResponse: - def __init__(self, mail: AsyncMailResource) -> None: - self._mail = mail +class AsyncLincResourceWithStreamingResponse: + def __init__(self, linc: AsyncLincResource) -> None: + self._linc = linc @cached_property def v1(self) -> AsyncV1ResourceWithStreamingResponse: - return AsyncV1ResourceWithStreamingResponse(self._mail.v1) + return AsyncV1ResourceWithStreamingResponse(self._linc.v1) diff --git a/src/casedev/resources/agent/__init__.py b/src/casedev/resources/linc/v1/__init__.py similarity index 51% rename from src/casedev/resources/agent/__init__.py rename to src/casedev/resources/linc/v1/__init__.py index 1c506f86..93ec4af8 100644 --- a/src/casedev/resources/agent/__init__.py +++ b/src/casedev/resources/linc/v1/__init__.py @@ -8,26 +8,26 @@ V1ResourceWithStreamingResponse, AsyncV1ResourceWithStreamingResponse, ) -from .agent import ( - AgentResource, - AsyncAgentResource, - AgentResourceWithRawResponse, - AsyncAgentResourceWithRawResponse, - AgentResourceWithStreamingResponse, - AsyncAgentResourceWithStreamingResponse, +from .sessions import ( + SessionsResource, + AsyncSessionsResource, + SessionsResourceWithRawResponse, + AsyncSessionsResourceWithRawResponse, + SessionsResourceWithStreamingResponse, + AsyncSessionsResourceWithStreamingResponse, ) __all__ = [ + "SessionsResource", + "AsyncSessionsResource", + "SessionsResourceWithRawResponse", + "AsyncSessionsResourceWithRawResponse", + "SessionsResourceWithStreamingResponse", + "AsyncSessionsResourceWithStreamingResponse", "V1Resource", "AsyncV1Resource", "V1ResourceWithRawResponse", "AsyncV1ResourceWithRawResponse", "V1ResourceWithStreamingResponse", "AsyncV1ResourceWithStreamingResponse", - "AgentResource", - "AsyncAgentResource", - "AgentResourceWithRawResponse", - "AsyncAgentResourceWithRawResponse", - "AgentResourceWithStreamingResponse", - "AsyncAgentResourceWithStreamingResponse", ] diff --git a/src/casedev/resources/agent/v1/run.py b/src/casedev/resources/linc/v1/sessions.py similarity index 51% rename from src/casedev/resources/agent/v1/run.py rename to src/casedev/resources/linc/v1/sessions.py index c70c8fc8..4a9ce336 100644 --- a/src/casedev/resources/agent/v1/run.py +++ b/src/casedev/resources/linc/v1/sessions.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Optional +from typing import Iterable, Optional from typing_extensions import Literal import httpx -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._types import Body, Omit, Query, Headers, NoneType, 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 @@ -17,81 +17,82 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...._streaming import Stream, AsyncStream from ...._base_client import make_request_options -from ....types.agent.v1 import run_list_params, run_watch_params, run_create_params, run_events_params -from ....types.agent.v1.run_exec_response import RunExecResponse -from ....types.agent.v1.run_list_response import RunListResponse -from ....types.agent.v1.run_watch_response import RunWatchResponse -from ....types.agent.v1.run_cancel_response import RunCancelResponse -from ....types.agent.v1.run_create_response import RunCreateResponse -from ....types.agent.v1.run_events_response import RunEventsResponse -from ....types.agent.v1.run_get_status_response import RunGetStatusResponse -from ....types.agent.v1.run_get_details_response import RunGetDetailsResponse +from ....types.linc.v1 import ( + session_cancel_params, + session_create_params, + session_send_rpc_params, + session_ingest_events_params, + session_retrieve_events_params, + session_retrieve_messages_params, +) -__all__ = ["RunResource", "AsyncRunResource"] +__all__ = ["SessionsResource", "AsyncSessionsResource"] -class RunResource(SyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ +class SessionsResource(SyncAPIResource): + """Durable, stateful legal agent sessions with sandboxed tools and files""" @cached_property - def with_raw_response(self) -> RunResourceWithRawResponse: + def with_raw_response(self) -> SessionsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return RunResourceWithRawResponse(self) + return SessionsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> RunResourceWithStreamingResponse: + def with_streaming_response(self) -> SessionsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return RunResourceWithStreamingResponse(self) + return SessionsResourceWithStreamingResponse(self) def create( self, *, - agent_id: str, - prompt: str, - callback_url: Optional[str] | Omit = omit, - guidance: Optional[str] | Omit = omit, + document_template_slugs: Optional[SequenceNotStr[str]] | Omit = omit, + idle_timeout_ms: Optional[int] | Omit = omit, + include_document_templates: Optional[bool] | Omit = omit, + instructions: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, + scoped_api_key: Optional[str] | Omit = omit, + service_tier: Literal["default", "priority"] | Omit = omit, + skill_slugs: Optional[SequenceNotStr[str]] | Omit = omit, + title: str | Omit = omit, + vault_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, extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCreateResponse: - """Creates a run in queued state. - - Call POST /agent/v1/run/:id/exec to start - execution. + ) -> None: + """ + Creates a Daytona-backed native Linc session with scoped Case.dev credentials. + This endpoint starts the sandbox actor only; messages and event replay use + separate endpoints. Args: - agent_id: ID of the agent to run + document_template_slugs: Specific document template slugs to inject into the using-document-templates + skill. - prompt: Task prompt for the agent + include_document_templates: When true, inject all active org document templates into the + using-document-templates skill. - callback_url: HTTPS callback URL to receive a notification when the run completes. Registered - atomically with the run — eliminates the race condition of calling /watch after - /exec. Additional watchers can still be added via POST /run/:id/watch. + instructions: Privileged C3-only hidden app instructions to append to the sandbox AGENTS.md. - guidance: Additional guidance for this run + scoped_api_key: Optional caller-provided scoped Case.dev API key for the runtime. - model: Override the agent default model for this run + service_tier: Processing tier for eligible OpenAI GPT models. Priority provides lower latency + at premium cost. - object_ids: Scope this run to specific vault object IDs. The agent will only be able to - access these objects during execution. + skill_slugs: Skills API slugs to install into the runtime sandbox before the native session + starts. extra_headers: Send extra headers @@ -101,54 +102,45 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - "/agent/v1/run", + "/linc/v1/sessions", body=maybe_transform( { - "agent_id": agent_id, - "prompt": prompt, - "callback_url": callback_url, - "guidance": guidance, + "document_template_slugs": document_template_slugs, + "idle_timeout_ms": idle_timeout_ms, + "include_document_templates": include_document_templates, + "instructions": instructions, "model": model, - "object_ids": object_ids, + "scoped_api_key": scoped_api_key, + "service_tier": service_tier, + "skill_slugs": skill_slugs, + "title": title, + "vault_ids": vault_ids, }, - run_create_params.RunCreateParams, + session_create_params.SessionCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunCreateResponse, + cast_to=NoneType, ) - def list( + def delete( self, + id: str, *, - agent_id: str | Omit = omit, - cursor: str | Omit = omit, - limit: int | Omit = omit, - status: Literal["queued", "running", "completed", "failed", "cancelled"] | 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, - ) -> RunListResponse: - """Lists agent runs for the authenticated organization. - - Supports filtering by - agent, status, and cursor-based pagination. + ) -> None: + """ + End native Linc session Args: - agent_id: Filter by agent ID - - cursor: Pagination cursor (run ID from previous page). Returns runs created before this - run. - - limit: Maximum number of runs to return (default 50, max 250) - - status: Filter by run status - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -157,43 +149,43 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get( - "/agent/v1/run", + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/linc/v1/sessions/{id}", id=id), options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "agent_id": agent_id, - "cursor": cursor, - "limit": limit, - "status": status, - }, - run_list_params.RunListParams, - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunListResponse, + cast_to=NoneType, ) def cancel( self, id: str, *, + clear_queue: bool | 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, - ) -> RunCancelResponse: - """Cancels a running or queued run. - - Idempotent — cancelling a finished run returns - its current status. + ) -> None: + """ + Sends an abort RPC to the session runtime, ending the current turn while keeping + the session alive. Body handling is intentionally lenient — cancel is a stop + control, so unknown fields are ignored and an invalid or missing body is treated + as empty rather than rejected. Args: + clear_queue: Also clear queued steering/follow-up messages so the abort leaves the agent + fully idle. Cleared texts are returned in the `response.data.clearedQueue` field + of the response body. Without it, messages still queued when the abort settles + are auto-continued as a new run. Runtimes older than the Linc release that + supports this flag ignore it: the abort still happens but the queue is left + untouched. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -204,32 +196,35 @@ def cancel( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - path_template("/agent/v1/run/{id}/cancel", id=id), + path_template("/linc/v1/sessions/{id}/cancel", id=id), + body=maybe_transform({"clear_queue": clear_queue}, session_cancel_params.SessionCancelParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunCancelResponse, + cast_to=NoneType, ) - def events( + def ingest_events( self, id: str, *, - last_event_id: int | Omit = omit, + frames: Iterable[session_ingest_events_params.Frame], # 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, - ) -> Stream[RunEventsResponse]: - """Streams real-time run events over SSE. + ) -> None: + """Runtime ingest endpoint for sandbox runtimes. - Supports replay using Last-Event-ID. + Frames are persisted for replay; + terminal frames emit the durable Linc session ended webhook. Args: - last_event_id: Replay events after this sequence number + frames: Native Linc event frames to persist for replay. extra_headers: Send extra headers @@ -241,38 +236,44 @@ def events( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} - return self._get( - path_template("/agent/v1/run/{id}/events", id=id), + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template("/linc/v1/sessions/{id}/events/ingest", id=id), + body=maybe_transform({"frames": frames}, session_ingest_events_params.SessionIngestEventsParams), options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"last_event_id": last_event_id}, run_events_params.RunEventsParams), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=str, - stream=True, - stream_cls=Stream[RunEventsResponse], + cast_to=NoneType, ) - def exec( + def retrieve_events( self, id: str, *, + after_seq: int | Omit = omit, + cursor: int | Omit = omit, + exclude_event_types: SequenceNotStr[str] | Omit = omit, + limit: 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, - ) -> RunExecResponse: - """Starts execution of a queued run. - - The agent runs in a durable workflow — poll - /run/:id/status for progress. + ) -> None: + """ + Returns persisted native Pi/Linc event envelopes after the requested cursor. + Live delivery is handled by the Linc stream service. Args: + after_seq: Alias for cursor. Ignored when cursor is also provided. + + cursor: Replay events with a sequence number greater than this cursor. + + exclude_event_types: Comma-separated Linc event types to omit from replay. + + limit: Maximum number of events to return. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -283,30 +284,53 @@ def exec( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - path_template("/agent/v1/run/{id}/exec", id=id), + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + path_template("/linc/v1/sessions/{id}/events", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after_seq": after_seq, + "cursor": cursor, + "exclude_event_types": exclude_event_types, + "limit": limit, + }, + session_retrieve_events_params.SessionRetrieveEventsParams, + ), ), - cast_to=RunExecResponse, + cast_to=NoneType, ) - def get_details( + def retrieve_messages( self, id: str, *, + after_seq: int | Omit = omit, + cursor: int | Omit = omit, + limit: 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, - ) -> RunGetDetailsResponse: + ) -> None: """ - Full audit trail for a run including output, steps (tool calls, text), and token - usage. + Returns completed Pi/Linc message entries derived from durable native Linc + events. This is the stable session-message read model for callers that need to + persist or recover chat history without depending on a live SSE stream. Args: + after_seq: Alias for cursor. Ignored when cursor is also provided. + + cursor: Replay messages with a source event sequence number greater than this cursor. + + limit: Maximum number of source events to scan for completed messages. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -317,15 +341,27 @@ def get_details( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._get( - path_template("/agent/v1/run/{id}/details", id=id), + path_template("/linc/v1/sessions/{id}/messages", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after_seq": after_seq, + "cursor": cursor, + "limit": limit, + }, + session_retrieve_messages_params.SessionRetrieveMessagesParams, + ), ), - cast_to=RunGetDetailsResponse, + cast_to=NoneType, ) - def get_status( + def retrieve_state( self, id: str, *, @@ -335,11 +371,9 @@ def get_status( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunGetStatusResponse: - """Lightweight status poll for a run. - - Use /run/:id/details for the full audit - trail. + ) -> None: + """ + Get native Linc session state Args: extra_headers: Send extra headers @@ -352,33 +386,38 @@ def get_status( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._get( - path_template("/agent/v1/run/{id}/status", id=id), + path_template("/linc/v1/sessions/{id}/state", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunGetStatusResponse, + cast_to=NoneType, ) - def watch( + def send_rpc( self, - id: str, + path_id: str, *, - callback_url: str, + type: str, + body_id: 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, - ) -> RunWatchResponse: - """Register a callback URL to receive notifications when the run completes. - - URL - must use https and must not point to a private network. + ) -> None: + """ + Forwards a native Pi/Linc RPC command object to the sandbox-local Linc bridge + unchanged. The route returns after Pi accepts or rejects the command; native + events are read through the events endpoint. Args: - callback_url: HTTPS URL to receive completion callback + type: Native Pi/Linc RPC command type. Prompt commands also require a string id for + idempotency. + + body_id: Command idempotency key. Required when type is prompt. extra_headers: Send extra headers @@ -388,78 +427,88 @@ def watch( timeout: Override the client-level default timeout for this request, in seconds """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - path_template("/agent/v1/run/{id}/watch", id=id), - body=maybe_transform({"callback_url": callback_url}, run_watch_params.RunWatchParams), + path_template("/linc/v1/sessions/{path_id}/rpc", path_id=path_id), + body=maybe_transform( + { + "type": type, + "body_id": body_id, + }, + session_send_rpc_params.SessionSendRpcParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunWatchResponse, + cast_to=NoneType, ) -class AsyncRunResource(AsyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ +class AsyncSessionsResource(AsyncAPIResource): + """Durable, stateful legal agent sessions with sandboxed tools and files""" @cached_property - def with_raw_response(self) -> AsyncRunResourceWithRawResponse: + def with_raw_response(self) -> AsyncSessionsResourceWithRawResponse: """ This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers """ - return AsyncRunResourceWithRawResponse(self) + return AsyncSessionsResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncRunResourceWithStreamingResponse: + def with_streaming_response(self) -> AsyncSessionsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response """ - return AsyncRunResourceWithStreamingResponse(self) + return AsyncSessionsResourceWithStreamingResponse(self) async def create( self, *, - agent_id: str, - prompt: str, - callback_url: Optional[str] | Omit = omit, - guidance: Optional[str] | Omit = omit, + document_template_slugs: Optional[SequenceNotStr[str]] | Omit = omit, + idle_timeout_ms: Optional[int] | Omit = omit, + include_document_templates: Optional[bool] | Omit = omit, + instructions: Optional[str] | Omit = omit, model: Optional[str] | Omit = omit, - object_ids: Optional[SequenceNotStr[str]] | Omit = omit, + scoped_api_key: Optional[str] | Omit = omit, + service_tier: Literal["default", "priority"] | Omit = omit, + skill_slugs: Optional[SequenceNotStr[str]] | Omit = omit, + title: str | Omit = omit, + vault_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, extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunCreateResponse: - """Creates a run in queued state. - - Call POST /agent/v1/run/:id/exec to start - execution. + ) -> None: + """ + Creates a Daytona-backed native Linc session with scoped Case.dev credentials. + This endpoint starts the sandbox actor only; messages and event replay use + separate endpoints. Args: - agent_id: ID of the agent to run + document_template_slugs: Specific document template slugs to inject into the using-document-templates + skill. - prompt: Task prompt for the agent + include_document_templates: When true, inject all active org document templates into the + using-document-templates skill. - callback_url: HTTPS callback URL to receive a notification when the run completes. Registered - atomically with the run — eliminates the race condition of calling /watch after - /exec. Additional watchers can still be added via POST /run/:id/watch. + instructions: Privileged C3-only hidden app instructions to append to the sandbox AGENTS.md. - guidance: Additional guidance for this run + scoped_api_key: Optional caller-provided scoped Case.dev API key for the runtime. - model: Override the agent default model for this run + service_tier: Processing tier for eligible OpenAI GPT models. Priority provides lower latency + at premium cost. - object_ids: Scope this run to specific vault object IDs. The agent will only be able to - access these objects during execution. + skill_slugs: Skills API slugs to install into the runtime sandbox before the native session + starts. extra_headers: Send extra headers @@ -469,54 +518,45 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - "/agent/v1/run", + "/linc/v1/sessions", body=await async_maybe_transform( { - "agent_id": agent_id, - "prompt": prompt, - "callback_url": callback_url, - "guidance": guidance, + "document_template_slugs": document_template_slugs, + "idle_timeout_ms": idle_timeout_ms, + "include_document_templates": include_document_templates, + "instructions": instructions, "model": model, - "object_ids": object_ids, + "scoped_api_key": scoped_api_key, + "service_tier": service_tier, + "skill_slugs": skill_slugs, + "title": title, + "vault_ids": vault_ids, }, - run_create_params.RunCreateParams, + session_create_params.SessionCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunCreateResponse, + cast_to=NoneType, ) - async def list( + async def delete( self, + id: str, *, - agent_id: str | Omit = omit, - cursor: str | Omit = omit, - limit: int | Omit = omit, - status: Literal["queued", "running", "completed", "failed", "cancelled"] | 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, - ) -> RunListResponse: - """Lists agent runs for the authenticated organization. - - Supports filtering by - agent, status, and cursor-based pagination. + ) -> None: + """ + End native Linc session Args: - agent_id: Filter by agent ID - - cursor: Pagination cursor (run ID from previous page). Returns runs created before this - run. - - limit: Maximum number of runs to return (default 50, max 250) - - status: Filter by run status - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -525,43 +565,43 @@ async def list( timeout: Override the client-level default timeout for this request, in seconds """ - return await self._get( - "/agent/v1/run", + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/linc/v1/sessions/{id}", id=id), options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "agent_id": agent_id, - "cursor": cursor, - "limit": limit, - "status": status, - }, - run_list_params.RunListParams, - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunListResponse, + cast_to=NoneType, ) async def cancel( self, id: str, *, + clear_queue: bool | 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, - ) -> RunCancelResponse: - """Cancels a running or queued run. - - Idempotent — cancelling a finished run returns - its current status. + ) -> None: + """ + Sends an abort RPC to the session runtime, ending the current turn while keeping + the session alive. Body handling is intentionally lenient — cancel is a stop + control, so unknown fields are ignored and an invalid or missing body is treated + as empty rather than rejected. Args: + clear_queue: Also clear queued steering/follow-up messages so the abort leaves the agent + fully idle. Cleared texts are returned in the `response.data.clearedQueue` field + of the response body. Without it, messages still queued when the abort settles + are auto-continued as a new run. Runtimes older than the Linc release that + supports this flag ignore it: the abort still happens but the queue is left + untouched. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -572,32 +612,35 @@ async def cancel( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - path_template("/agent/v1/run/{id}/cancel", id=id), + path_template("/linc/v1/sessions/{id}/cancel", id=id), + body=await async_maybe_transform({"clear_queue": clear_queue}, session_cancel_params.SessionCancelParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunCancelResponse, + cast_to=NoneType, ) - async def events( + async def ingest_events( self, id: str, *, - last_event_id: int | Omit = omit, + frames: Iterable[session_ingest_events_params.Frame], # 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, - ) -> AsyncStream[RunEventsResponse]: - """Streams real-time run events over SSE. + ) -> None: + """Runtime ingest endpoint for sandbox runtimes. - Supports replay using Last-Event-ID. + Frames are persisted for replay; + terminal frames emit the durable Linc session ended webhook. Args: - last_event_id: Replay events after this sequence number + frames: Native Linc event frames to persist for replay. extra_headers: Send extra headers @@ -609,38 +652,46 @@ async def events( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} - return await self._get( - path_template("/agent/v1/run/{id}/events", id=id), + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template("/linc/v1/sessions/{id}/events/ingest", id=id), + body=await async_maybe_transform( + {"frames": frames}, session_ingest_events_params.SessionIngestEventsParams + ), options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"last_event_id": last_event_id}, run_events_params.RunEventsParams), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=str, - stream=True, - stream_cls=AsyncStream[RunEventsResponse], + cast_to=NoneType, ) - async def exec( + async def retrieve_events( self, id: str, *, + after_seq: int | Omit = omit, + cursor: int | Omit = omit, + exclude_event_types: SequenceNotStr[str] | Omit = omit, + limit: 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, - ) -> RunExecResponse: - """Starts execution of a queued run. - - The agent runs in a durable workflow — poll - /run/:id/status for progress. + ) -> None: + """ + Returns persisted native Pi/Linc event envelopes after the requested cursor. + Live delivery is handled by the Linc stream service. Args: + after_seq: Alias for cursor. Ignored when cursor is also provided. + + cursor: Replay events with a sequence number greater than this cursor. + + exclude_event_types: Comma-separated Linc event types to omit from replay. + + limit: Maximum number of events to return. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -651,30 +702,53 @@ async def exec( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - path_template("/agent/v1/run/{id}/exec", id=id), + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + path_template("/linc/v1/sessions/{id}/events", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after_seq": after_seq, + "cursor": cursor, + "exclude_event_types": exclude_event_types, + "limit": limit, + }, + session_retrieve_events_params.SessionRetrieveEventsParams, + ), ), - cast_to=RunExecResponse, + cast_to=NoneType, ) - async def get_details( + async def retrieve_messages( self, id: str, *, + after_seq: int | Omit = omit, + cursor: int | Omit = omit, + limit: 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, - ) -> RunGetDetailsResponse: + ) -> None: """ - Full audit trail for a run including output, steps (tool calls, text), and token - usage. + Returns completed Pi/Linc message entries derived from durable native Linc + events. This is the stable session-message read model for callers that need to + persist or recover chat history without depending on a live SSE stream. Args: + after_seq: Alias for cursor. Ignored when cursor is also provided. + + cursor: Replay messages with a source event sequence number greater than this cursor. + + limit: Maximum number of source events to scan for completed messages. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -685,15 +759,27 @@ async def get_details( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._get( - path_template("/agent/v1/run/{id}/details", id=id), + path_template("/linc/v1/sessions/{id}/messages", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after_seq": after_seq, + "cursor": cursor, + "limit": limit, + }, + session_retrieve_messages_params.SessionRetrieveMessagesParams, + ), ), - cast_to=RunGetDetailsResponse, + cast_to=NoneType, ) - async def get_status( + async def retrieve_state( self, id: str, *, @@ -703,11 +789,9 @@ async def get_status( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RunGetStatusResponse: - """Lightweight status poll for a run. - - Use /run/:id/details for the full audit - trail. + ) -> None: + """ + Get native Linc session state Args: extra_headers: Send extra headers @@ -720,33 +804,38 @@ async def get_status( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._get( - path_template("/agent/v1/run/{id}/status", id=id), + path_template("/linc/v1/sessions/{id}/state", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunGetStatusResponse, + cast_to=NoneType, ) - async def watch( + async def send_rpc( self, - id: str, + path_id: str, *, - callback_url: str, + type: str, + body_id: 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, - ) -> RunWatchResponse: - """Register a callback URL to receive notifications when the run completes. - - URL - must use https and must not point to a private network. + ) -> None: + """ + Forwards a native Pi/Linc RPC command object to the sandbox-local Linc bridge + unchanged. The route returns after Pi accepts or rejects the command; native + events are read through the events endpoint. Args: - callback_url: HTTPS URL to receive completion callback + type: Native Pi/Linc RPC command type. Prompt commands also require a string id for + idempotency. + + body_id: Command idempotency key. Required when type is prompt. extra_headers: Send extra headers @@ -756,133 +845,140 @@ async def watch( timeout: Override the client-level default timeout for this request, in seconds """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not path_id: + raise ValueError(f"Expected a non-empty value for `path_id` but received {path_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - path_template("/agent/v1/run/{id}/watch", id=id), - body=await async_maybe_transform({"callback_url": callback_url}, run_watch_params.RunWatchParams), + path_template("/linc/v1/sessions/{path_id}/rpc", path_id=path_id), + body=await async_maybe_transform( + { + "type": type, + "body_id": body_id, + }, + session_send_rpc_params.SessionSendRpcParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=RunWatchResponse, + cast_to=NoneType, ) -class RunResourceWithRawResponse: - def __init__(self, run: RunResource) -> None: - self._run = run +class SessionsResourceWithRawResponse: + def __init__(self, sessions: SessionsResource) -> None: + self._sessions = sessions self.create = to_raw_response_wrapper( - run.create, + sessions.create, ) - self.list = to_raw_response_wrapper( - run.list, + self.delete = to_raw_response_wrapper( + sessions.delete, ) self.cancel = to_raw_response_wrapper( - run.cancel, + sessions.cancel, ) - self.events = to_raw_response_wrapper( - run.events, + self.ingest_events = to_raw_response_wrapper( + sessions.ingest_events, ) - self.exec = to_raw_response_wrapper( - run.exec, + self.retrieve_events = to_raw_response_wrapper( + sessions.retrieve_events, ) - self.get_details = to_raw_response_wrapper( - run.get_details, + self.retrieve_messages = to_raw_response_wrapper( + sessions.retrieve_messages, ) - self.get_status = to_raw_response_wrapper( - run.get_status, + self.retrieve_state = to_raw_response_wrapper( + sessions.retrieve_state, ) - self.watch = to_raw_response_wrapper( - run.watch, + self.send_rpc = to_raw_response_wrapper( + sessions.send_rpc, ) -class AsyncRunResourceWithRawResponse: - def __init__(self, run: AsyncRunResource) -> None: - self._run = run +class AsyncSessionsResourceWithRawResponse: + def __init__(self, sessions: AsyncSessionsResource) -> None: + self._sessions = sessions self.create = async_to_raw_response_wrapper( - run.create, + sessions.create, ) - self.list = async_to_raw_response_wrapper( - run.list, + self.delete = async_to_raw_response_wrapper( + sessions.delete, ) self.cancel = async_to_raw_response_wrapper( - run.cancel, + sessions.cancel, ) - self.events = async_to_raw_response_wrapper( - run.events, + self.ingest_events = async_to_raw_response_wrapper( + sessions.ingest_events, ) - self.exec = async_to_raw_response_wrapper( - run.exec, + self.retrieve_events = async_to_raw_response_wrapper( + sessions.retrieve_events, ) - self.get_details = async_to_raw_response_wrapper( - run.get_details, + self.retrieve_messages = async_to_raw_response_wrapper( + sessions.retrieve_messages, ) - self.get_status = async_to_raw_response_wrapper( - run.get_status, + self.retrieve_state = async_to_raw_response_wrapper( + sessions.retrieve_state, ) - self.watch = async_to_raw_response_wrapper( - run.watch, + self.send_rpc = async_to_raw_response_wrapper( + sessions.send_rpc, ) -class RunResourceWithStreamingResponse: - def __init__(self, run: RunResource) -> None: - self._run = run +class SessionsResourceWithStreamingResponse: + def __init__(self, sessions: SessionsResource) -> None: + self._sessions = sessions self.create = to_streamed_response_wrapper( - run.create, + sessions.create, ) - self.list = to_streamed_response_wrapper( - run.list, + self.delete = to_streamed_response_wrapper( + sessions.delete, ) self.cancel = to_streamed_response_wrapper( - run.cancel, + sessions.cancel, ) - self.events = to_streamed_response_wrapper( - run.events, + self.ingest_events = to_streamed_response_wrapper( + sessions.ingest_events, ) - self.exec = to_streamed_response_wrapper( - run.exec, + self.retrieve_events = to_streamed_response_wrapper( + sessions.retrieve_events, ) - self.get_details = to_streamed_response_wrapper( - run.get_details, + self.retrieve_messages = to_streamed_response_wrapper( + sessions.retrieve_messages, ) - self.get_status = to_streamed_response_wrapper( - run.get_status, + self.retrieve_state = to_streamed_response_wrapper( + sessions.retrieve_state, ) - self.watch = to_streamed_response_wrapper( - run.watch, + self.send_rpc = to_streamed_response_wrapper( + sessions.send_rpc, ) -class AsyncRunResourceWithStreamingResponse: - def __init__(self, run: AsyncRunResource) -> None: - self._run = run +class AsyncSessionsResourceWithStreamingResponse: + def __init__(self, sessions: AsyncSessionsResource) -> None: + self._sessions = sessions self.create = async_to_streamed_response_wrapper( - run.create, + sessions.create, ) - self.list = async_to_streamed_response_wrapper( - run.list, + self.delete = async_to_streamed_response_wrapper( + sessions.delete, ) self.cancel = async_to_streamed_response_wrapper( - run.cancel, + sessions.cancel, ) - self.events = async_to_streamed_response_wrapper( - run.events, + self.ingest_events = async_to_streamed_response_wrapper( + sessions.ingest_events, ) - self.exec = async_to_streamed_response_wrapper( - run.exec, + self.retrieve_events = async_to_streamed_response_wrapper( + sessions.retrieve_events, ) - self.get_details = async_to_streamed_response_wrapper( - run.get_details, + self.retrieve_messages = async_to_streamed_response_wrapper( + sessions.retrieve_messages, ) - self.get_status = async_to_streamed_response_wrapper( - run.get_status, + self.retrieve_state = async_to_streamed_response_wrapper( + sessions.retrieve_state, ) - self.watch = async_to_streamed_response_wrapper( - run.watch, + self.send_rpc = async_to_streamed_response_wrapper( + sessions.send_rpc, ) diff --git a/src/casedev/resources/mail/v1/v1.py b/src/casedev/resources/linc/v1/v1.py similarity index 59% rename from src/casedev/resources/mail/v1/v1.py rename to src/casedev/resources/linc/v1/v1.py index 2bdc9298..6e356c43 100644 --- a/src/casedev/resources/mail/v1/v1.py +++ b/src/casedev/resources/linc/v1/v1.py @@ -2,13 +2,13 @@ from __future__ import annotations -from .inboxes import ( - InboxesResource, - AsyncInboxesResource, - InboxesResourceWithRawResponse, - AsyncInboxesResourceWithRawResponse, - InboxesResourceWithStreamingResponse, - AsyncInboxesResourceWithStreamingResponse, +from .sessions import ( + SessionsResource, + AsyncSessionsResource, + SessionsResourceWithRawResponse, + AsyncSessionsResourceWithRawResponse, + SessionsResourceWithStreamingResponse, + AsyncSessionsResourceWithStreamingResponse, ) from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -18,11 +18,9 @@ class V1Resource(SyncAPIResource): @cached_property - def inboxes(self) -> InboxesResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return InboxesResource(self._client) + def sessions(self) -> SessionsResource: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return SessionsResource(self._client) @cached_property def with_raw_response(self) -> V1ResourceWithRawResponse: @@ -46,11 +44,9 @@ def with_streaming_response(self) -> V1ResourceWithStreamingResponse: class AsyncV1Resource(AsyncAPIResource): @cached_property - def inboxes(self) -> AsyncInboxesResource: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncInboxesResource(self._client) + def sessions(self) -> AsyncSessionsResource: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return AsyncSessionsResource(self._client) @cached_property def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: @@ -77,11 +73,9 @@ def __init__(self, v1: V1Resource) -> None: self._v1 = v1 @cached_property - def inboxes(self) -> InboxesResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return InboxesResourceWithRawResponse(self._v1.inboxes) + def sessions(self) -> SessionsResourceWithRawResponse: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return SessionsResourceWithRawResponse(self._v1.sessions) class AsyncV1ResourceWithRawResponse: @@ -89,11 +83,9 @@ def __init__(self, v1: AsyncV1Resource) -> None: self._v1 = v1 @cached_property - def inboxes(self) -> AsyncInboxesResourceWithRawResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncInboxesResourceWithRawResponse(self._v1.inboxes) + def sessions(self) -> AsyncSessionsResourceWithRawResponse: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return AsyncSessionsResourceWithRawResponse(self._v1.sessions) class V1ResourceWithStreamingResponse: @@ -101,11 +93,9 @@ def __init__(self, v1: V1Resource) -> None: self._v1 = v1 @cached_property - def inboxes(self) -> InboxesResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return InboxesResourceWithStreamingResponse(self._v1.inboxes) + def sessions(self) -> SessionsResourceWithStreamingResponse: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return SessionsResourceWithStreamingResponse(self._v1.sessions) class AsyncV1ResourceWithStreamingResponse: @@ -113,8 +103,6 @@ def __init__(self, v1: AsyncV1Resource) -> None: self._v1 = v1 @cached_property - def inboxes(self) -> AsyncInboxesResourceWithStreamingResponse: - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - return AsyncInboxesResourceWithStreamingResponse(self._v1.inboxes) + def sessions(self) -> AsyncSessionsResourceWithStreamingResponse: + """Durable, stateful legal agent sessions with sandboxed tools and files""" + return AsyncSessionsResourceWithStreamingResponse(self._v1.sessions) diff --git a/src/casedev/resources/llm/v1/chat.py b/src/casedev/resources/llm/v1/chat.py index 10f4bde3..55a9d098 100644 --- a/src/casedev/resources/llm/v1/chat.py +++ b/src/casedev/resources/llm/v1/chat.py @@ -74,8 +74,9 @@ def create_completion( Args: messages: List of messages comprising the conversation - casemark_show_reasoning: CaseMark-only: when true, allows reasoning fields in responses. Defaults to - false (reasoning is suppressed). + casemark_show_reasoning: CaseMark-only: controls whether reasoning fields appear in responses. Defaults + to false (suppressed) for most CaseMark models; defaults to true for + casemark/core-potassium. frequency_penalty: Frequency penalty parameter @@ -173,8 +174,9 @@ async def create_completion( Args: messages: List of messages comprising the conversation - casemark_show_reasoning: CaseMark-only: when true, allows reasoning fields in responses. Defaults to - false (reasoning is suppressed). + casemark_show_reasoning: CaseMark-only: controls whether reasoning fields appear in responses. Defaults + to false (suppressed) for most CaseMark models; defaults to true for + casemark/core-potassium. frequency_penalty: Frequency penalty parameter diff --git a/src/casedev/resources/mail/v1/__init__.py b/src/casedev/resources/mail/v1/__init__.py deleted file mode 100644 index fd8876c6..00000000 --- a/src/casedev/resources/mail/v1/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .inboxes import ( - InboxesResource, - AsyncInboxesResource, - InboxesResourceWithRawResponse, - AsyncInboxesResourceWithRawResponse, - InboxesResourceWithStreamingResponse, - AsyncInboxesResourceWithStreamingResponse, -) - -__all__ = [ - "InboxesResource", - "AsyncInboxesResource", - "InboxesResourceWithRawResponse", - "AsyncInboxesResourceWithRawResponse", - "InboxesResourceWithStreamingResponse", - "AsyncInboxesResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/mail/v1/inboxes.py b/src/casedev/resources/mail/v1/inboxes.py deleted file mode 100644 index c55c95a3..00000000 --- a/src/casedev/resources/mail/v1/inboxes.py +++ /dev/null @@ -1,1056 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ...._types import Body, Omit, Query, Headers, NoneType, 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 ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.mail.v1 import inbox_create_params, inbox_set_policy_params - -__all__ = ["InboxesResource", "AsyncInboxesResource"] - - -class InboxesResource(SyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - - @cached_property - def with_raw_response(self) -> InboxesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return InboxesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InboxesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return InboxesResourceWithStreamingResponse(self) - - def create( - self, - *, - address: str | Omit = omit, - display_name: 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, - ) -> None: - """ - Create an inbox owned by the authenticated organization. - - 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( - "/mail/v1/inboxes", - body=maybe_transform( - { - "address": address, - "display_name": display_name, - }, - inbox_create_params.InboxCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def retrieve( - self, - inbox_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, - ) -> None: - """ - Get an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template("/mail/v1/inboxes/{inbox_id}", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list( - 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, - ) -> None: - """List inboxes owned by the authenticated organization.""" - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - "/mail/v1/inboxes", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def delete( - self, - inbox_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, - ) -> None: - """ - Delete an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - path_template("/mail/v1/inboxes/{inbox_id}", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def get_attachment( - self, - attachment_id: str, - *, - inbox_id: str, - message_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, - ) -> None: - """ - Get attachment metadata for a message in an inbox owned by the authenticated - organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - if not attachment_id: - raise ValueError(f"Expected a non-empty value for `attachment_id` but received {attachment_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}", - inbox_id=inbox_id, - message_id=message_id, - attachment_id=attachment_id, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def get_message( - self, - message_id: str, - *, - inbox_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, - ) -> None: - """ - Get a message for an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}", inbox_id=inbox_id, message_id=message_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def get_policy( - self, - inbox_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, - ) -> None: - """ - Get the sender allowlist and send/reply/read access rules for an inbox owned by - the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template("/mail/v1/inboxes/{inbox_id}/policy", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_messages( - self, - inbox_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, - ) -> None: - """ - List messages for an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template("/mail/v1/inboxes/{inbox_id}/messages", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def reply( - self, - message_id: str, - *, - inbox_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, - ) -> None: - """ - Reply to a message in an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}/reply", inbox_id=inbox_id, message_id=message_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def send( - self, - inbox_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, - ) -> None: - """ - Send a message from an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - path_template("/mail/v1/inboxes/{inbox_id}/messages/send", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def set_policy( - self, - inbox_id: str, - *, - allowed_sender_patterns: SequenceNotStr[str] | Omit = omit, - enforce_sender_allowlist: bool | Omit = omit, - read_access_rules: SequenceNotStr[str] | Omit = omit, - reply_access_rules: SequenceNotStr[str] | Omit = omit, - send_access_rules: 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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Set the sender allowlist and send/reply/read access rules for an inbox owned by - the authenticated organization. - - Args: - allowed_sender_patterns: Exact emails, @domain rules, or \\** - - read_access_rules: Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - - reply_access_rules: Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - - send_access_rules: Rules like organization, user:, api_key, api_key:, clerk_session, or \\** - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._put( - path_template("/mail/v1/inboxes/{inbox_id}/policy", inbox_id=inbox_id), - body=maybe_transform( - { - "allowed_sender_patterns": allowed_sender_patterns, - "enforce_sender_allowlist": enforce_sender_allowlist, - "read_access_rules": read_access_rules, - "reply_access_rules": reply_access_rules, - "send_access_rules": send_access_rules, - }, - inbox_set_policy_params.InboxSetPolicyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncInboxesResource(AsyncAPIResource): - """ - Create, manage, and execute AI agents with tool access, sandbox environments, and async run workflows - """ - - @cached_property - def with_raw_response(self) -> AsyncInboxesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncInboxesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInboxesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncInboxesResourceWithStreamingResponse(self) - - async def create( - self, - *, - address: str | Omit = omit, - display_name: 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, - ) -> None: - """ - Create an inbox owned by the authenticated organization. - - 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( - "/mail/v1/inboxes", - body=await async_maybe_transform( - { - "address": address, - "display_name": display_name, - }, - inbox_create_params.InboxCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def retrieve( - self, - inbox_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, - ) -> None: - """ - Get an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template("/mail/v1/inboxes/{inbox_id}", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def list( - 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, - ) -> None: - """List inboxes owned by the authenticated organization.""" - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - "/mail/v1/inboxes", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def delete( - self, - inbox_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, - ) -> None: - """ - Delete an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - path_template("/mail/v1/inboxes/{inbox_id}", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def get_attachment( - self, - attachment_id: str, - *, - inbox_id: str, - message_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, - ) -> None: - """ - Get attachment metadata for a message in an inbox owned by the authenticated - organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - if not attachment_id: - raise ValueError(f"Expected a non-empty value for `attachment_id` but received {attachment_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}", - inbox_id=inbox_id, - message_id=message_id, - attachment_id=attachment_id, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def get_message( - self, - message_id: str, - *, - inbox_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, - ) -> None: - """ - Get a message for an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}", inbox_id=inbox_id, message_id=message_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def get_policy( - self, - inbox_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, - ) -> None: - """ - Get the sender allowlist and send/reply/read access rules for an inbox owned by - the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template("/mail/v1/inboxes/{inbox_id}/policy", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def list_messages( - self, - inbox_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, - ) -> None: - """ - List messages for an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template("/mail/v1/inboxes/{inbox_id}/messages", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def reply( - self, - message_id: str, - *, - inbox_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, - ) -> None: - """ - Reply to a message in an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - path_template( - "/mail/v1/inboxes/{inbox_id}/messages/{message_id}/reply", inbox_id=inbox_id, message_id=message_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def send( - self, - inbox_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, - ) -> None: - """ - Send a message from an inbox owned by the authenticated organization. - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - path_template("/mail/v1/inboxes/{inbox_id}/messages/send", inbox_id=inbox_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def set_policy( - self, - inbox_id: str, - *, - allowed_sender_patterns: SequenceNotStr[str] | Omit = omit, - enforce_sender_allowlist: bool | Omit = omit, - read_access_rules: SequenceNotStr[str] | Omit = omit, - reply_access_rules: SequenceNotStr[str] | Omit = omit, - send_access_rules: 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, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Set the sender allowlist and send/reply/read access rules for an inbox owned by - the authenticated organization. - - Args: - allowed_sender_patterns: Exact emails, @domain rules, or \\** - - read_access_rules: Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - - reply_access_rules: Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - - send_access_rules: Rules like organization, user:, api_key, api_key:, clerk_session, or \\** - - 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 inbox_id: - raise ValueError(f"Expected a non-empty value for `inbox_id` but received {inbox_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._put( - path_template("/mail/v1/inboxes/{inbox_id}/policy", inbox_id=inbox_id), - body=await async_maybe_transform( - { - "allowed_sender_patterns": allowed_sender_patterns, - "enforce_sender_allowlist": enforce_sender_allowlist, - "read_access_rules": read_access_rules, - "reply_access_rules": reply_access_rules, - "send_access_rules": send_access_rules, - }, - inbox_set_policy_params.InboxSetPolicyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class InboxesResourceWithRawResponse: - def __init__(self, inboxes: InboxesResource) -> None: - self._inboxes = inboxes - - self.create = to_raw_response_wrapper( - inboxes.create, - ) - self.retrieve = to_raw_response_wrapper( - inboxes.retrieve, - ) - self.list = to_raw_response_wrapper( - inboxes.list, - ) - self.delete = to_raw_response_wrapper( - inboxes.delete, - ) - self.get_attachment = to_raw_response_wrapper( - inboxes.get_attachment, - ) - self.get_message = to_raw_response_wrapper( - inboxes.get_message, - ) - self.get_policy = to_raw_response_wrapper( - inboxes.get_policy, - ) - self.list_messages = to_raw_response_wrapper( - inboxes.list_messages, - ) - self.reply = to_raw_response_wrapper( - inboxes.reply, - ) - self.send = to_raw_response_wrapper( - inboxes.send, - ) - self.set_policy = to_raw_response_wrapper( - inboxes.set_policy, - ) - - -class AsyncInboxesResourceWithRawResponse: - def __init__(self, inboxes: AsyncInboxesResource) -> None: - self._inboxes = inboxes - - self.create = async_to_raw_response_wrapper( - inboxes.create, - ) - self.retrieve = async_to_raw_response_wrapper( - inboxes.retrieve, - ) - self.list = async_to_raw_response_wrapper( - inboxes.list, - ) - self.delete = async_to_raw_response_wrapper( - inboxes.delete, - ) - self.get_attachment = async_to_raw_response_wrapper( - inboxes.get_attachment, - ) - self.get_message = async_to_raw_response_wrapper( - inboxes.get_message, - ) - self.get_policy = async_to_raw_response_wrapper( - inboxes.get_policy, - ) - self.list_messages = async_to_raw_response_wrapper( - inboxes.list_messages, - ) - self.reply = async_to_raw_response_wrapper( - inboxes.reply, - ) - self.send = async_to_raw_response_wrapper( - inboxes.send, - ) - self.set_policy = async_to_raw_response_wrapper( - inboxes.set_policy, - ) - - -class InboxesResourceWithStreamingResponse: - def __init__(self, inboxes: InboxesResource) -> None: - self._inboxes = inboxes - - self.create = to_streamed_response_wrapper( - inboxes.create, - ) - self.retrieve = to_streamed_response_wrapper( - inboxes.retrieve, - ) - self.list = to_streamed_response_wrapper( - inboxes.list, - ) - self.delete = to_streamed_response_wrapper( - inboxes.delete, - ) - self.get_attachment = to_streamed_response_wrapper( - inboxes.get_attachment, - ) - self.get_message = to_streamed_response_wrapper( - inboxes.get_message, - ) - self.get_policy = to_streamed_response_wrapper( - inboxes.get_policy, - ) - self.list_messages = to_streamed_response_wrapper( - inboxes.list_messages, - ) - self.reply = to_streamed_response_wrapper( - inboxes.reply, - ) - self.send = to_streamed_response_wrapper( - inboxes.send, - ) - self.set_policy = to_streamed_response_wrapper( - inboxes.set_policy, - ) - - -class AsyncInboxesResourceWithStreamingResponse: - def __init__(self, inboxes: AsyncInboxesResource) -> None: - self._inboxes = inboxes - - self.create = async_to_streamed_response_wrapper( - inboxes.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - inboxes.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - inboxes.list, - ) - self.delete = async_to_streamed_response_wrapper( - inboxes.delete, - ) - self.get_attachment = async_to_streamed_response_wrapper( - inboxes.get_attachment, - ) - self.get_message = async_to_streamed_response_wrapper( - inboxes.get_message, - ) - self.get_policy = async_to_streamed_response_wrapper( - inboxes.get_policy, - ) - self.list_messages = async_to_streamed_response_wrapper( - inboxes.list_messages, - ) - self.reply = async_to_streamed_response_wrapper( - inboxes.reply, - ) - self.send = async_to_streamed_response_wrapper( - inboxes.send, - ) - self.set_policy = async_to_streamed_response_wrapper( - inboxes.set_policy, - ) diff --git a/src/casedev/resources/matters/v1/work_items.py b/src/casedev/resources/matters/v1/work_items.py index 9057488e..8a56f1fd 100644 --- a/src/casedev/resources/matters/v1/work_items.py +++ b/src/casedev/resources/matters/v1/work_items.py @@ -269,8 +269,7 @@ def decide( work_item_id: str, *, id: str, - decision: Literal["approve", "revise", "block", "reassign"], - agent_type_id: Optional[str] | Omit = omit, + decision: Literal["approve", "block"], metadata: Dict[str, object] | Omit = omit, reason: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -280,10 +279,8 @@ def decide( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Approve, revise, block, or reassign a work item. - - Used by humans or agents to - move work items through their lifecycle. + """ + Approve or block a work item. Args: extra_headers: Send extra headers @@ -304,7 +301,6 @@ def decide( body=maybe_transform( { "decision": decision, - "agent_type_id": agent_type_id, "metadata": metadata, "reason": reason, }, @@ -316,43 +312,6 @@ def decide( cast_to=NoneType, ) - def list_executions( - self, - work_item_id: str, - *, - 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, - ) -> None: - """ - List execution attempts for a work item, including agent and run linkage. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not work_item_id: - raise ValueError(f"Expected a non-empty value for `work_item_id` but received {work_item_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._get( - path_template("/matters/v1/{id}/work-items/{work_item_id}/executions", id=id, work_item_id=work_item_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - class AsyncWorkItemsResource(AsyncAPIResource): """Matter-native legal workspaces and orchestration primitives""" @@ -594,8 +553,7 @@ async def decide( work_item_id: str, *, id: str, - decision: Literal["approve", "revise", "block", "reassign"], - agent_type_id: Optional[str] | Omit = omit, + decision: Literal["approve", "block"], metadata: Dict[str, object] | Omit = omit, reason: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -605,10 +563,8 @@ async def decide( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Approve, revise, block, or reassign a work item. - - Used by humans or agents to - move work items through their lifecycle. + """ + Approve or block a work item. Args: extra_headers: Send extra headers @@ -629,7 +585,6 @@ async def decide( body=await async_maybe_transform( { "decision": decision, - "agent_type_id": agent_type_id, "metadata": metadata, "reason": reason, }, @@ -641,43 +596,6 @@ async def decide( cast_to=NoneType, ) - async def list_executions( - self, - work_item_id: str, - *, - 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, - ) -> None: - """ - List execution attempts for a work item, including agent and run linkage. - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not work_item_id: - raise ValueError(f"Expected a non-empty value for `work_item_id` but received {work_item_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._get( - path_template("/matters/v1/{id}/work-items/{work_item_id}/executions", id=id, work_item_id=work_item_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - class WorkItemsResourceWithRawResponse: def __init__(self, work_items: WorkItemsResource) -> None: @@ -698,9 +616,6 @@ def __init__(self, work_items: WorkItemsResource) -> None: self.decide = to_raw_response_wrapper( work_items.decide, ) - self.list_executions = to_raw_response_wrapper( - work_items.list_executions, - ) class AsyncWorkItemsResourceWithRawResponse: @@ -722,9 +637,6 @@ def __init__(self, work_items: AsyncWorkItemsResource) -> None: self.decide = async_to_raw_response_wrapper( work_items.decide, ) - self.list_executions = async_to_raw_response_wrapper( - work_items.list_executions, - ) class WorkItemsResourceWithStreamingResponse: @@ -746,9 +658,6 @@ def __init__(self, work_items: WorkItemsResource) -> None: self.decide = to_streamed_response_wrapper( work_items.decide, ) - self.list_executions = to_streamed_response_wrapper( - work_items.list_executions, - ) class AsyncWorkItemsResourceWithStreamingResponse: @@ -770,6 +679,3 @@ def __init__(self, work_items: AsyncWorkItemsResource) -> None: self.decide = async_to_streamed_response_wrapper( work_items.decide, ) - self.list_executions = async_to_streamed_response_wrapper( - work_items.list_executions, - ) diff --git a/src/casedev/resources/media/v1/clips.py b/src/casedev/resources/media/v1/clips.py index eb973be0..f8bfd21c 100644 --- a/src/casedev/resources/media/v1/clips.py +++ b/src/casedev/resources/media/v1/clips.py @@ -20,6 +20,8 @@ class ClipsResource(SyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + @cached_property def with_raw_response(self) -> ClipsResourceWithRawResponse: """ @@ -95,6 +97,8 @@ def retrieve( class AsyncClipsResource(AsyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + @cached_property def with_raw_response(self) -> AsyncClipsResourceWithRawResponse: """ diff --git a/src/casedev/resources/media/v1/transcripts/__init__.py b/src/casedev/resources/media/v1/transcripts/__init__.py index f957041b..33a94bae 100644 --- a/src/casedev/resources/media/v1/transcripts/__init__.py +++ b/src/casedev/resources/media/v1/transcripts/__init__.py @@ -8,6 +8,14 @@ SearchResourceWithStreamingResponse, AsyncSearchResourceWithStreamingResponse, ) +from .retrieve import ( + RetrieveResource, + AsyncRetrieveResource, + RetrieveResourceWithRawResponse, + AsyncRetrieveResourceWithRawResponse, + RetrieveResourceWithStreamingResponse, + AsyncRetrieveResourceWithStreamingResponse, +) from .transcripts import ( TranscriptsResource, AsyncTranscriptsResource, @@ -24,6 +32,12 @@ "AsyncSearchResourceWithRawResponse", "SearchResourceWithStreamingResponse", "AsyncSearchResourceWithStreamingResponse", + "RetrieveResource", + "AsyncRetrieveResource", + "RetrieveResourceWithRawResponse", + "AsyncRetrieveResourceWithRawResponse", + "RetrieveResourceWithStreamingResponse", + "AsyncRetrieveResourceWithStreamingResponse", "TranscriptsResource", "AsyncTranscriptsResource", "TranscriptsResourceWithRawResponse", diff --git a/src/casedev/resources/media/v1/transcripts/retrieve.py b/src/casedev/resources/media/v1/transcripts/retrieve.py new file mode 100644 index 00000000..72615a57 --- /dev/null +++ b/src/casedev/resources/media/v1/transcripts/retrieve.py @@ -0,0 +1,203 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._utils import maybe_transform, async_maybe_transform +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._base_client import make_request_options +from .....types.media.v1.transcripts import retrieve_create_params +from .....types.media.v1.transcripts.retrieve_create_response import RetrieveCreateResponse + +__all__ = ["RetrieveResource", "AsyncRetrieveResource"] + + +class RetrieveResource(SyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + + @cached_property + def with_raw_response(self) -> RetrieveResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return RetrieveResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RetrieveResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return RetrieveResourceWithStreamingResponse(self) + + def create( + self, + *, + object_id: str, + vault_id: str, + transcript: retrieve_create_params.Transcript | 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, + ) -> RetrieveCreateResponse: + """ + Retrieves the full transcript text for a vault transcript object or an + audio/video source object with a completed transcription job. When object_id is + a source media object, access to that source object grants access to its + generated transcript artifact. + + Args: + object_id: Object ID for either the source audio/video file or transcript artifact. + + vault_id: Vault ID containing the source media or transcript object. + + transcript: Alternative nested transcript object reference. + + 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( + "/media/v1/transcripts/retrieve", + body=maybe_transform( + { + "object_id": object_id, + "vault_id": vault_id, + "transcript": transcript, + }, + retrieve_create_params.RetrieveCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RetrieveCreateResponse, + ) + + +class AsyncRetrieveResource(AsyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + + @cached_property + def with_raw_response(self) -> AsyncRetrieveResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers + """ + return AsyncRetrieveResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRetrieveResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response + """ + return AsyncRetrieveResourceWithStreamingResponse(self) + + async def create( + self, + *, + object_id: str, + vault_id: str, + transcript: retrieve_create_params.Transcript | 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, + ) -> RetrieveCreateResponse: + """ + Retrieves the full transcript text for a vault transcript object or an + audio/video source object with a completed transcription job. When object_id is + a source media object, access to that source object grants access to its + generated transcript artifact. + + Args: + object_id: Object ID for either the source audio/video file or transcript artifact. + + vault_id: Vault ID containing the source media or transcript object. + + transcript: Alternative nested transcript object reference. + + 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( + "/media/v1/transcripts/retrieve", + body=await async_maybe_transform( + { + "object_id": object_id, + "vault_id": vault_id, + "transcript": transcript, + }, + retrieve_create_params.RetrieveCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RetrieveCreateResponse, + ) + + +class RetrieveResourceWithRawResponse: + def __init__(self, retrieve: RetrieveResource) -> None: + self._retrieve = retrieve + + self.create = to_raw_response_wrapper( + retrieve.create, + ) + + +class AsyncRetrieveResourceWithRawResponse: + def __init__(self, retrieve: AsyncRetrieveResource) -> None: + self._retrieve = retrieve + + self.create = async_to_raw_response_wrapper( + retrieve.create, + ) + + +class RetrieveResourceWithStreamingResponse: + def __init__(self, retrieve: RetrieveResource) -> None: + self._retrieve = retrieve + + self.create = to_streamed_response_wrapper( + retrieve.create, + ) + + +class AsyncRetrieveResourceWithStreamingResponse: + def __init__(self, retrieve: AsyncRetrieveResource) -> None: + self._retrieve = retrieve + + self.create = async_to_streamed_response_wrapper( + retrieve.create, + ) diff --git a/src/casedev/resources/media/v1/transcripts/search.py b/src/casedev/resources/media/v1/transcripts/search.py index 6e5854ca..5375797c 100644 --- a/src/casedev/resources/media/v1/transcripts/search.py +++ b/src/casedev/resources/media/v1/transcripts/search.py @@ -19,6 +19,8 @@ class SearchResource(SyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + @cached_property def with_raw_response(self) -> SearchResourceWithRawResponse: """ @@ -60,6 +62,8 @@ def create( class AsyncSearchResource(AsyncAPIResource): + """Transcript retrieval and captioned media clip generation""" + @cached_property def with_raw_response(self) -> AsyncSearchResourceWithRawResponse: """ diff --git a/src/casedev/resources/media/v1/transcripts/transcripts.py b/src/casedev/resources/media/v1/transcripts/transcripts.py index f5423428..f3a14fca 100644 --- a/src/casedev/resources/media/v1/transcripts/transcripts.py +++ b/src/casedev/resources/media/v1/transcripts/transcripts.py @@ -10,6 +10,14 @@ SearchResourceWithStreamingResponse, AsyncSearchResourceWithStreamingResponse, ) +from .retrieve import ( + RetrieveResource, + AsyncRetrieveResource, + RetrieveResourceWithRawResponse, + AsyncRetrieveResourceWithRawResponse, + RetrieveResourceWithStreamingResponse, + AsyncRetrieveResourceWithStreamingResponse, +) from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -19,8 +27,14 @@ class TranscriptsResource(SyncAPIResource): @cached_property def search(self) -> SearchResource: + """Transcript retrieval and captioned media clip generation""" return SearchResource(self._client) + @cached_property + def retrieve(self) -> RetrieveResource: + """Transcript retrieval and captioned media clip generation""" + return RetrieveResource(self._client) + @cached_property def with_raw_response(self) -> TranscriptsResourceWithRawResponse: """ @@ -44,8 +58,14 @@ def with_streaming_response(self) -> TranscriptsResourceWithStreamingResponse: class AsyncTranscriptsResource(AsyncAPIResource): @cached_property def search(self) -> AsyncSearchResource: + """Transcript retrieval and captioned media clip generation""" return AsyncSearchResource(self._client) + @cached_property + def retrieve(self) -> AsyncRetrieveResource: + """Transcript retrieval and captioned media clip generation""" + return AsyncRetrieveResource(self._client) + @cached_property def with_raw_response(self) -> AsyncTranscriptsResourceWithRawResponse: """ @@ -72,8 +92,14 @@ def __init__(self, transcripts: TranscriptsResource) -> None: @cached_property def search(self) -> SearchResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" return SearchResourceWithRawResponse(self._transcripts.search) + @cached_property + def retrieve(self) -> RetrieveResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" + return RetrieveResourceWithRawResponse(self._transcripts.retrieve) + class AsyncTranscriptsResourceWithRawResponse: def __init__(self, transcripts: AsyncTranscriptsResource) -> None: @@ -81,8 +107,14 @@ def __init__(self, transcripts: AsyncTranscriptsResource) -> None: @cached_property def search(self) -> AsyncSearchResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" return AsyncSearchResourceWithRawResponse(self._transcripts.search) + @cached_property + def retrieve(self) -> AsyncRetrieveResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" + return AsyncRetrieveResourceWithRawResponse(self._transcripts.retrieve) + class TranscriptsResourceWithStreamingResponse: def __init__(self, transcripts: TranscriptsResource) -> None: @@ -90,8 +122,14 @@ def __init__(self, transcripts: TranscriptsResource) -> None: @cached_property def search(self) -> SearchResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" return SearchResourceWithStreamingResponse(self._transcripts.search) + @cached_property + def retrieve(self) -> RetrieveResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" + return RetrieveResourceWithStreamingResponse(self._transcripts.retrieve) + class AsyncTranscriptsResourceWithStreamingResponse: def __init__(self, transcripts: AsyncTranscriptsResource) -> None: @@ -99,4 +137,10 @@ def __init__(self, transcripts: AsyncTranscriptsResource) -> None: @cached_property def search(self) -> AsyncSearchResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" return AsyncSearchResourceWithStreamingResponse(self._transcripts.search) + + @cached_property + def retrieve(self) -> AsyncRetrieveResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" + return AsyncRetrieveResourceWithStreamingResponse(self._transcripts.retrieve) diff --git a/src/casedev/resources/media/v1/v1.py b/src/casedev/resources/media/v1/v1.py index b506b4bc..b05a90d7 100644 --- a/src/casedev/resources/media/v1/v1.py +++ b/src/casedev/resources/media/v1/v1.py @@ -27,6 +27,7 @@ class V1Resource(SyncAPIResource): @cached_property def clips(self) -> ClipsResource: + """Transcript retrieval and captioned media clip generation""" return ClipsResource(self._client) @cached_property @@ -56,6 +57,7 @@ def with_streaming_response(self) -> V1ResourceWithStreamingResponse: class AsyncV1Resource(AsyncAPIResource): @cached_property def clips(self) -> AsyncClipsResource: + """Transcript retrieval and captioned media clip generation""" return AsyncClipsResource(self._client) @cached_property @@ -88,6 +90,7 @@ def __init__(self, v1: V1Resource) -> None: @cached_property def clips(self) -> ClipsResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" return ClipsResourceWithRawResponse(self._v1.clips) @cached_property @@ -101,6 +104,7 @@ def __init__(self, v1: AsyncV1Resource) -> None: @cached_property def clips(self) -> AsyncClipsResourceWithRawResponse: + """Transcript retrieval and captioned media clip generation""" return AsyncClipsResourceWithRawResponse(self._v1.clips) @cached_property @@ -114,6 +118,7 @@ def __init__(self, v1: V1Resource) -> None: @cached_property def clips(self) -> ClipsResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" return ClipsResourceWithStreamingResponse(self._v1.clips) @cached_property @@ -127,6 +132,7 @@ def __init__(self, v1: AsyncV1Resource) -> None: @cached_property def clips(self) -> AsyncClipsResourceWithStreamingResponse: + """Transcript retrieval and captioned media clip generation""" return AsyncClipsResourceWithStreamingResponse(self._v1.clips) @cached_property diff --git a/src/casedev/resources/ocr/v1.py b/src/casedev/resources/ocr/v1.py index 0b727b62..8ccb4e78 100644 --- a/src/casedev/resources/ocr/v1.py +++ b/src/casedev/resources/ocr/v1.py @@ -68,11 +68,11 @@ def retrieve( ) -> V1RetrieveResponse: """Retrieve the status and results of an OCR job. - Returns job progress, extracted - text, and metadata when processing is complete. + Returns job progress and + metadata; full extracted text is included only when include_text=true. Args: - include_text: Include full OCR text in completed responses (default: true) + include_text: Include full OCR text in completed responses (default: false) extra_headers: Send extra headers @@ -236,11 +236,11 @@ async def retrieve( ) -> V1RetrieveResponse: """Retrieve the status and results of an OCR job. - Returns job progress, extracted - text, and metadata when processing is complete. + Returns job progress and + metadata; full extracted text is included only when include_text=true. Args: - include_text: Include full OCR text in completed responses (default: true) + include_text: Include full OCR text in completed responses (default: false) extra_headers: Send extra headers diff --git a/src/casedev/resources/search/search.py b/src/casedev/resources/search/search.py index d1cab2aa..28dbc2ba 100644 --- a/src/casedev/resources/search/search.py +++ b/src/casedev/resources/search/search.py @@ -19,7 +19,7 @@ class SearchResource(SyncAPIResource): @cached_property def v1(self) -> V1Resource: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return V1Resource(self._client) @cached_property @@ -45,7 +45,7 @@ def with_streaming_response(self) -> SearchResourceWithStreamingResponse: class AsyncSearchResource(AsyncAPIResource): @cached_property def v1(self) -> AsyncV1Resource: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return AsyncV1Resource(self._client) @cached_property @@ -74,7 +74,7 @@ def __init__(self, search: SearchResource) -> None: @cached_property def v1(self) -> V1ResourceWithRawResponse: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return V1ResourceWithRawResponse(self._search.v1) @@ -84,7 +84,7 @@ def __init__(self, search: AsyncSearchResource) -> None: @cached_property def v1(self) -> AsyncV1ResourceWithRawResponse: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return AsyncV1ResourceWithRawResponse(self._search.v1) @@ -94,7 +94,7 @@ def __init__(self, search: SearchResource) -> None: @cached_property def v1(self) -> V1ResourceWithStreamingResponse: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return V1ResourceWithStreamingResponse(self._search.v1) @@ -104,5 +104,5 @@ def __init__(self, search: AsyncSearchResource) -> None: @cached_property def v1(self) -> AsyncV1ResourceWithStreamingResponse: - """Web search, AI answers, and deep research""" + """Web search and AI answers""" return AsyncV1ResourceWithStreamingResponse(self._search.v1) diff --git a/src/casedev/resources/search/v1.py b/src/casedev/resources/search/v1.py index 2a55097f..a45aac49 100644 --- a/src/casedev/resources/search/v1.py +++ b/src/casedev/resources/search/v1.py @@ -9,7 +9,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -19,26 +19,17 @@ async_to_streamed_response_wrapper, ) from ..._base_client import make_request_options -from ...types.search import ( - v1_answer_params, - v1_search_params, - v1_similar_params, - v1_contents_params, - v1_research_params, - v1_retrieve_research_params, -) +from ...types.search import v1_answer_params, v1_search_params, v1_similar_params, v1_contents_params from ...types.search.v1_answer_response import V1AnswerResponse from ...types.search.v1_search_response import V1SearchResponse from ...types.search.v1_similar_response import V1SimilarResponse from ...types.search.v1_contents_response import V1ContentsResponse -from ...types.search.v1_research_response import V1ResearchResponse -from ...types.search.v1_retrieve_research_response import V1RetrieveResearchResponse __all__ = ["V1Resource", "AsyncV1Resource"] class V1Resource(SyncAPIResource): - """Web search, AI answers, and deep research""" + """Web search and AI answers""" @cached_property def with_raw_response(self) -> V1ResourceWithRawResponse: @@ -220,112 +211,6 @@ def contents( cast_to=V1ContentsResponse, ) - def research( - self, - *, - instructions: str, - model: Literal["fast", "normal", "pro"] | Omit = omit, - output_schema: object | Omit = omit, - query: 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, - ) -> V1ResearchResponse: - """ - Performs deep research by conducting multi-step analysis, gathering information - from multiple sources, and providing comprehensive insights. Ideal for legal - research, case analysis, and due diligence investigations. - - Args: - instructions: Research instructions or query - - model: Research quality level - fast (quick), normal (balanced), pro (comprehensive) - - output_schema: Optional JSON schema to structure the research output - - query: Alias for instructions (for convenience) - - 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( - "/search/v1/research", - body=maybe_transform( - { - "instructions": instructions, - "model": model, - "output_schema": output_schema, - "query": query, - }, - v1_research_params.V1ResearchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1ResearchResponse, - ) - - def retrieve_research( - self, - id: str, - *, - events: str | Omit = omit, - stream: bool | 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, - ) -> V1RetrieveResearchResponse: - """Retrieve the status and results of a deep research task by ID. - - Supports both - standard JSON responses and streaming for real-time updates as the research - progresses. Research tasks analyze topics comprehensively using web search and - AI synthesis. - - Args: - events: Filter specific event types for streaming - - stream: Enable streaming for real-time updates - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - path_template("/search/v1/research/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "events": events, - "stream": stream, - }, - v1_retrieve_research_params.V1RetrieveResearchParams, - ), - ), - cast_to=V1RetrieveResearchResponse, - ) - def search( self, *, @@ -499,7 +384,7 @@ def similar( class AsyncV1Resource(AsyncAPIResource): - """Web search, AI answers, and deep research""" + """Web search and AI answers""" @cached_property def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: @@ -681,112 +566,6 @@ async def contents( cast_to=V1ContentsResponse, ) - async def research( - self, - *, - instructions: str, - model: Literal["fast", "normal", "pro"] | Omit = omit, - output_schema: object | Omit = omit, - query: 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, - ) -> V1ResearchResponse: - """ - Performs deep research by conducting multi-step analysis, gathering information - from multiple sources, and providing comprehensive insights. Ideal for legal - research, case analysis, and due diligence investigations. - - Args: - instructions: Research instructions or query - - model: Research quality level - fast (quick), normal (balanced), pro (comprehensive) - - output_schema: Optional JSON schema to structure the research output - - query: Alias for instructions (for convenience) - - 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( - "/search/v1/research", - body=await async_maybe_transform( - { - "instructions": instructions, - "model": model, - "output_schema": output_schema, - "query": query, - }, - v1_research_params.V1ResearchParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=V1ResearchResponse, - ) - - async def retrieve_research( - self, - id: str, - *, - events: str | Omit = omit, - stream: bool | 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, - ) -> V1RetrieveResearchResponse: - """Retrieve the status and results of a deep research task by ID. - - Supports both - standard JSON responses and streaming for real-time updates as the research - progresses. Research tasks analyze topics comprehensively using web search and - AI synthesis. - - Args: - events: Filter specific event types for streaming - - stream: Enable streaming for real-time updates - - 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 id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - path_template("/search/v1/research/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "events": events, - "stream": stream, - }, - v1_retrieve_research_params.V1RetrieveResearchParams, - ), - ), - cast_to=V1RetrieveResearchResponse, - ) - async def search( self, *, @@ -969,12 +748,6 @@ def __init__(self, v1: V1Resource) -> None: self.contents = to_raw_response_wrapper( v1.contents, ) - self.research = to_raw_response_wrapper( - v1.research, - ) - self.retrieve_research = to_raw_response_wrapper( - v1.retrieve_research, - ) self.search = to_raw_response_wrapper( v1.search, ) @@ -993,12 +766,6 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.contents = async_to_raw_response_wrapper( v1.contents, ) - self.research = async_to_raw_response_wrapper( - v1.research, - ) - self.retrieve_research = async_to_raw_response_wrapper( - v1.retrieve_research, - ) self.search = async_to_raw_response_wrapper( v1.search, ) @@ -1017,12 +784,6 @@ def __init__(self, v1: V1Resource) -> None: self.contents = to_streamed_response_wrapper( v1.contents, ) - self.research = to_streamed_response_wrapper( - v1.research, - ) - self.retrieve_research = to_streamed_response_wrapper( - v1.retrieve_research, - ) self.search = to_streamed_response_wrapper( v1.search, ) @@ -1041,12 +802,6 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.contents = async_to_streamed_response_wrapper( v1.contents, ) - self.research = async_to_streamed_response_wrapper( - v1.research, - ) - self.retrieve_research = async_to_streamed_response_wrapper( - v1.retrieve_research, - ) self.search = async_to_streamed_response_wrapper( v1.search, ) diff --git a/src/casedev/resources/superdoc/__init__.py b/src/casedev/resources/superdoc/__init__.py deleted file mode 100644 index 18e3a98c..00000000 --- a/src/casedev/resources/superdoc/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .superdoc import ( - SuperdocResource, - AsyncSuperdocResource, - SuperdocResourceWithRawResponse, - AsyncSuperdocResourceWithRawResponse, - SuperdocResourceWithStreamingResponse, - AsyncSuperdocResourceWithStreamingResponse, -) - -__all__ = [ - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", - "SuperdocResource", - "AsyncSuperdocResource", - "SuperdocResourceWithRawResponse", - "AsyncSuperdocResourceWithRawResponse", - "SuperdocResourceWithStreamingResponse", - "AsyncSuperdocResourceWithStreamingResponse", -] diff --git a/src/casedev/resources/superdoc/superdoc.py b/src/casedev/resources/superdoc/superdoc.py deleted file mode 100644 index 560543a1..00000000 --- a/src/casedev/resources/superdoc/superdoc.py +++ /dev/null @@ -1,108 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["SuperdocResource", "AsyncSuperdocResource"] - - -class SuperdocResource(SyncAPIResource): - @cached_property - def v1(self) -> V1Resource: - """Document conversion and template automation""" - return V1Resource(self._client) - - @cached_property - def with_raw_response(self) -> SuperdocResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return SuperdocResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SuperdocResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return SuperdocResourceWithStreamingResponse(self) - - -class AsyncSuperdocResource(AsyncAPIResource): - @cached_property - def v1(self) -> AsyncV1Resource: - """Document conversion and template automation""" - return AsyncV1Resource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncSuperdocResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncSuperdocResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSuperdocResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncSuperdocResourceWithStreamingResponse(self) - - -class SuperdocResourceWithRawResponse: - def __init__(self, superdoc: SuperdocResource) -> None: - self._superdoc = superdoc - - @cached_property - def v1(self) -> V1ResourceWithRawResponse: - """Document conversion and template automation""" - return V1ResourceWithRawResponse(self._superdoc.v1) - - -class AsyncSuperdocResourceWithRawResponse: - def __init__(self, superdoc: AsyncSuperdocResource) -> None: - self._superdoc = superdoc - - @cached_property - def v1(self) -> AsyncV1ResourceWithRawResponse: - """Document conversion and template automation""" - return AsyncV1ResourceWithRawResponse(self._superdoc.v1) - - -class SuperdocResourceWithStreamingResponse: - def __init__(self, superdoc: SuperdocResource) -> None: - self._superdoc = superdoc - - @cached_property - def v1(self) -> V1ResourceWithStreamingResponse: - """Document conversion and template automation""" - return V1ResourceWithStreamingResponse(self._superdoc.v1) - - -class AsyncSuperdocResourceWithStreamingResponse: - def __init__(self, superdoc: AsyncSuperdocResource) -> None: - self._superdoc = superdoc - - @cached_property - def v1(self) -> AsyncV1ResourceWithStreamingResponse: - """Document conversion and template automation""" - return AsyncV1ResourceWithStreamingResponse(self._superdoc.v1) diff --git a/src/casedev/resources/superdoc/v1.py b/src/casedev/resources/superdoc/v1.py deleted file mode 100644 index 9192d6cb..00000000 --- a/src/casedev/resources/superdoc/v1.py +++ /dev/null @@ -1,356 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Mapping, Iterable, cast -from typing_extensions import Literal - -import httpx - -from ..._files import deepcopy_with_paths -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import extract_files, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_custom_raw_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.superdoc import v1_convert_params, v1_annotate_params - -__all__ = ["V1Resource", "AsyncV1Resource"] - - -class V1Resource(SyncAPIResource): - """Document conversion and template automation""" - - @cached_property - def with_raw_response(self) -> V1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return V1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return V1ResourceWithStreamingResponse(self) - - def annotate( - self, - *, - document: v1_annotate_params.Document, - fields: Iterable[v1_annotate_params.Field], - output_format: Literal["docx", "pdf"] | 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: - """Populate fields inside a DOCX template using SuperDoc annotations. - - Supports - text, images, dates, and numbers. Can target individual fields by ID or multiple - fields by group. - - Args: - document: Document source - provide either URL or base64 - - fields: Fields to populate in the template - - output_format: Output format for the annotated document - - 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": "application/pdf", **(extra_headers or {})} - return self._post( - "/superdoc/v1/annotate", - body=maybe_transform( - { - "document": document, - "fields": fields, - "output_format": output_format, - }, - v1_annotate_params.V1AnnotateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BinaryAPIResponse, - ) - - def convert( - self, - *, - from_: Literal["docx", "md", "html"], - document_base64: str | Omit = omit, - document_url: str | Omit = omit, - to: Literal["pdf", "docx"] | 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: - """Convert documents between formats using SuperDoc. - - Supports DOCX to PDF, Markdown - to DOCX, and HTML to DOCX conversions. - - Args: - from_: Source format of the document - - document_base64: Base64-encoded document content - - document_url: URL to the document to convert - - to: Target format for conversion - - 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": "application/pdf", **(extra_headers or {})} - body = deepcopy_with_paths( - { - "from_": from_, - "document_base64": document_base64, - "document_url": document_url, - "to": to, - }, - [["file"]], - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - if files: - # 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( - "/superdoc/v1/convert", - body=maybe_transform(body, v1_convert_params.V1ConvertParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BinaryAPIResponse, - ) - - -class AsyncV1Resource(AsyncAPIResource): - """Document conversion and template automation""" - - @cached_property - def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/CaseMark/casedev-python#accessing-raw-response-data-eg-headers - """ - return AsyncV1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/CaseMark/casedev-python#with_streaming_response - """ - return AsyncV1ResourceWithStreamingResponse(self) - - async def annotate( - self, - *, - document: v1_annotate_params.Document, - fields: Iterable[v1_annotate_params.Field], - output_format: Literal["docx", "pdf"] | 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: - """Populate fields inside a DOCX template using SuperDoc annotations. - - Supports - text, images, dates, and numbers. Can target individual fields by ID or multiple - fields by group. - - Args: - document: Document source - provide either URL or base64 - - fields: Fields to populate in the template - - output_format: Output format for the annotated document - - 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": "application/pdf", **(extra_headers or {})} - return await self._post( - "/superdoc/v1/annotate", - body=await async_maybe_transform( - { - "document": document, - "fields": fields, - "output_format": output_format, - }, - v1_annotate_params.V1AnnotateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AsyncBinaryAPIResponse, - ) - - async def convert( - self, - *, - from_: Literal["docx", "md", "html"], - document_base64: str | Omit = omit, - document_url: str | Omit = omit, - to: Literal["pdf", "docx"] | 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: - """Convert documents between formats using SuperDoc. - - Supports DOCX to PDF, Markdown - to DOCX, and HTML to DOCX conversions. - - Args: - from_: Source format of the document - - document_base64: Base64-encoded document content - - document_url: URL to the document to convert - - to: Target format for conversion - - 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": "application/pdf", **(extra_headers or {})} - body = deepcopy_with_paths( - { - "from_": from_, - "document_base64": document_base64, - "document_url": document_url, - "to": to, - }, - [["file"]], - ) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - if files: - # 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( - "/superdoc/v1/convert", - body=await async_maybe_transform(body, v1_convert_params.V1ConvertParams), - files=files, - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AsyncBinaryAPIResponse, - ) - - -class V1ResourceWithRawResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.annotate = to_custom_raw_response_wrapper( - v1.annotate, - BinaryAPIResponse, - ) - self.convert = to_custom_raw_response_wrapper( - v1.convert, - BinaryAPIResponse, - ) - - -class AsyncV1ResourceWithRawResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.annotate = async_to_custom_raw_response_wrapper( - v1.annotate, - AsyncBinaryAPIResponse, - ) - self.convert = async_to_custom_raw_response_wrapper( - v1.convert, - AsyncBinaryAPIResponse, - ) - - -class V1ResourceWithStreamingResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - self.annotate = to_custom_streamed_response_wrapper( - v1.annotate, - StreamedBinaryAPIResponse, - ) - self.convert = to_custom_streamed_response_wrapper( - v1.convert, - StreamedBinaryAPIResponse, - ) - - -class AsyncV1ResourceWithStreamingResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - self.annotate = async_to_custom_streamed_response_wrapper( - v1.annotate, - AsyncStreamedBinaryAPIResponse, - ) - self.convert = async_to_custom_streamed_response_wrapper( - v1.convert, - AsyncStreamedBinaryAPIResponse, - ) diff --git a/src/casedev/resources/translate/translate.py b/src/casedev/resources/translate/translate.py index 05d4e741..6a061c71 100644 --- a/src/casedev/resources/translate/translate.py +++ b/src/casedev/resources/translate/translate.py @@ -19,6 +19,7 @@ class TranslateResource(SyncAPIResource): @cached_property def v1(self) -> V1Resource: + """Language detection and translation for multilingual legal workflows""" return V1Resource(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> TranslateResourceWithStreamingResponse: class AsyncTranslateResource(AsyncAPIResource): @cached_property def v1(self) -> AsyncV1Resource: + """Language detection and translation for multilingual legal workflows""" return AsyncV1Resource(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, translate: TranslateResource) -> None: @cached_property def v1(self) -> V1ResourceWithRawResponse: + """Language detection and translation for multilingual legal workflows""" return V1ResourceWithRawResponse(self._translate.v1) @@ -81,6 +84,7 @@ def __init__(self, translate: AsyncTranslateResource) -> None: @cached_property def v1(self) -> AsyncV1ResourceWithRawResponse: + """Language detection and translation for multilingual legal workflows""" return AsyncV1ResourceWithRawResponse(self._translate.v1) @@ -90,6 +94,7 @@ def __init__(self, translate: TranslateResource) -> None: @cached_property def v1(self) -> V1ResourceWithStreamingResponse: + """Language detection and translation for multilingual legal workflows""" return V1ResourceWithStreamingResponse(self._translate.v1) @@ -99,4 +104,5 @@ def __init__(self, translate: AsyncTranslateResource) -> None: @cached_property def v1(self) -> AsyncV1ResourceWithStreamingResponse: + """Language detection and translation for multilingual legal workflows""" return AsyncV1ResourceWithStreamingResponse(self._translate.v1) diff --git a/src/casedev/resources/translate/v1.py b/src/casedev/resources/translate/v1.py index 9fc9b92e..a25eb671 100644 --- a/src/casedev/resources/translate/v1.py +++ b/src/casedev/resources/translate/v1.py @@ -2,23 +2,47 @@ from __future__ import annotations -from typing import Union +from typing import Union, Mapping, cast from typing_extensions import Literal import httpx -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._files import deepcopy_with_paths +from ..._types import ( + Body, + Omit, + Query, + Headers, + NotGiven, + FileTypes, + SequenceNotStr, + omit, + not_given, +) +from ..._utils import extract_files, 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 ..._base_client import make_request_options -from ...types.translate import v1_detect_params, v1_translate_params, v1_list_languages_params +from ...types.translate import ( + v1_detect_params, + v1_translate_params, + v1_list_languages_params, + v1_translate_document_params, +) from ...types.translate.v1_detect_response import V1DetectResponse from ...types.translate.v1_translate_response import V1TranslateResponse from ...types.translate.v1_list_languages_response import V1ListLanguagesResponse @@ -27,6 +51,8 @@ class V1Resource(SyncAPIResource): + """Language detection and translation for multilingual legal workflows""" + @cached_property def with_raw_response(self) -> V1ResourceWithRawResponse: """ @@ -191,8 +217,68 @@ def translate( cast_to=V1TranslateResponse, ) + def translate_document( + self, + *, + file: FileTypes, + target: str, + source: 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: + """Translate one TXT, DOCX, or searchable PDF document. + + DOCX and PDF translations + preserve the source document format and retain as much layout and formatting as + possible. + + Args: + file: TXT, DOCX, or searchable PDF document (max 20MB) + + target: Target BCP-47 language code + + source: Optional source BCP-47 language code. Auto-detected when omitted. + + 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": "application/octet-stream", **(extra_headers or {})} + body = deepcopy_with_paths( + { + "file": file, + "target": target, + "source": source, + }, + [["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", **(extra_headers or {})} + return self._post( + "/translate/v1/document", + body=maybe_transform(body, v1_translate_document_params.V1TranslateDocumentParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryAPIResponse, + ) + class AsyncV1Resource(AsyncAPIResource): + """Language detection and translation for multilingual legal workflows""" + @cached_property def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: """ @@ -357,6 +443,64 @@ async def translate( cast_to=V1TranslateResponse, ) + async def translate_document( + self, + *, + file: FileTypes, + target: str, + source: 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: + """Translate one TXT, DOCX, or searchable PDF document. + + DOCX and PDF translations + preserve the source document format and retain as much layout and formatting as + possible. + + Args: + file: TXT, DOCX, or searchable PDF document (max 20MB) + + target: Target BCP-47 language code + + source: Optional source BCP-47 language code. Auto-detected when omitted. + + 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": "application/octet-stream", **(extra_headers or {})} + body = deepcopy_with_paths( + { + "file": file, + "target": target, + "source": source, + }, + [["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", **(extra_headers or {})} + return await self._post( + "/translate/v1/document", + body=await async_maybe_transform(body, v1_translate_document_params.V1TranslateDocumentParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AsyncBinaryAPIResponse, + ) + class V1ResourceWithRawResponse: def __init__(self, v1: V1Resource) -> None: @@ -371,6 +515,10 @@ def __init__(self, v1: V1Resource) -> None: self.translate = to_raw_response_wrapper( v1.translate, ) + self.translate_document = to_custom_raw_response_wrapper( + v1.translate_document, + BinaryAPIResponse, + ) class AsyncV1ResourceWithRawResponse: @@ -386,6 +534,10 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.translate = async_to_raw_response_wrapper( v1.translate, ) + self.translate_document = async_to_custom_raw_response_wrapper( + v1.translate_document, + AsyncBinaryAPIResponse, + ) class V1ResourceWithStreamingResponse: @@ -401,6 +553,10 @@ def __init__(self, v1: V1Resource) -> None: self.translate = to_streamed_response_wrapper( v1.translate, ) + self.translate_document = to_custom_streamed_response_wrapper( + v1.translate_document, + StreamedBinaryAPIResponse, + ) class AsyncV1ResourceWithStreamingResponse: @@ -416,3 +572,7 @@ def __init__(self, v1: AsyncV1Resource) -> None: self.translate = async_to_streamed_response_wrapper( v1.translate, ) + self.translate_document = async_to_custom_streamed_response_wrapper( + v1.translate_document, + AsyncStreamedBinaryAPIResponse, + ) diff --git a/src/casedev/resources/usage/v1/v1.py b/src/casedev/resources/usage/v1/v1.py index 2bf86174..f8e3571f 100644 --- a/src/casedev/resources/usage/v1/v1.py +++ b/src/casedev/resources/usage/v1/v1.py @@ -63,6 +63,8 @@ def retrieve( self, *, granularity: Literal["summary", "daily"] | Omit = omit, + group_by: Literal["lincSessionId"] | Omit = omit, + linc_session_id: str | Omit = omit, period_end: Union[str, datetime] | Omit = omit, period_start: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -81,6 +83,12 @@ def retrieve( Args: granularity: Whether to return period totals only or include daily buckets. + group_by: Optionally include usage groups keyed by native Linc session id. Only + Linc-session-attributable usage is grouped. + + linc_session_id: Restrict usage to a native Linc session. The session must belong to the + authenticated organization. + period_end: Period end date. Defaults to now. period_start: Period start date. Defaults to the start of the current calendar month. @@ -104,6 +112,8 @@ def retrieve( query=maybe_transform( { "granularity": granularity, + "group_by": group_by, + "linc_session_id": linc_session_id, "period_end": period_end, "period_start": period_start, }, @@ -145,6 +155,8 @@ async def retrieve( self, *, granularity: Literal["summary", "daily"] | Omit = omit, + group_by: Literal["lincSessionId"] | Omit = omit, + linc_session_id: str | Omit = omit, period_end: Union[str, datetime] | Omit = omit, period_start: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -163,6 +175,12 @@ async def retrieve( Args: granularity: Whether to return period totals only or include daily buckets. + group_by: Optionally include usage groups keyed by native Linc session id. Only + Linc-session-attributable usage is grouped. + + linc_session_id: Restrict usage to a native Linc session. The session must belong to the + authenticated organization. + period_end: Period end date. Defaults to now. period_start: Period start date. Defaults to the start of the current calendar month. @@ -186,6 +204,8 @@ async def retrieve( query=await async_maybe_transform( { "granularity": granularity, + "group_by": group_by, + "linc_session_id": linc_session_id, "period_end": period_end, "period_start": period_start, }, diff --git a/src/casedev/resources/vault/__init__.py b/src/casedev/resources/vault/__init__.py index 89502278..228888f6 100644 --- a/src/casedev/resources/vault/__init__.py +++ b/src/casedev/resources/vault/__init__.py @@ -40,14 +40,6 @@ ObjectsResourceWithStreamingResponse, AsyncObjectsResourceWithStreamingResponse, ) -from .graphrag import ( - GraphragResource, - AsyncGraphragResource, - GraphragResourceWithRawResponse, - AsyncGraphragResourceWithRawResponse, - GraphragResourceWithStreamingResponse, - AsyncGraphragResourceWithStreamingResponse, -) from .multipart import ( MultipartResource, AsyncMultipartResource, @@ -64,12 +56,6 @@ "AsyncEventsResourceWithRawResponse", "EventsResourceWithStreamingResponse", "AsyncEventsResourceWithStreamingResponse", - "GraphragResource", - "AsyncGraphragResource", - "GraphragResourceWithRawResponse", - "AsyncGraphragResourceWithRawResponse", - "GraphragResourceWithStreamingResponse", - "AsyncGraphragResourceWithStreamingResponse", "GroupsResource", "AsyncGroupsResource", "GroupsResourceWithRawResponse", diff --git a/src/casedev/resources/vault/events/events.py b/src/casedev/resources/vault/events/events.py index 99f36d96..e4e9be8e 100644 --- a/src/casedev/resources/vault/events/events.py +++ b/src/casedev/resources/vault/events/events.py @@ -19,7 +19,7 @@ class EventsResource(SyncAPIResource): @cached_property def subscriptions(self) -> SubscriptionsResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return SubscriptionsResource(self._client) @cached_property @@ -45,7 +45,7 @@ def with_streaming_response(self) -> EventsResourceWithStreamingResponse: class AsyncEventsResource(AsyncAPIResource): @cached_property def subscriptions(self) -> AsyncSubscriptionsResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return AsyncSubscriptionsResource(self._client) @cached_property @@ -74,7 +74,7 @@ def __init__(self, events: EventsResource) -> None: @cached_property def subscriptions(self) -> SubscriptionsResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return SubscriptionsResourceWithRawResponse(self._events.subscriptions) @@ -84,7 +84,7 @@ def __init__(self, events: AsyncEventsResource) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return AsyncSubscriptionsResourceWithRawResponse(self._events.subscriptions) @@ -94,7 +94,7 @@ def __init__(self, events: EventsResource) -> None: @cached_property def subscriptions(self) -> SubscriptionsResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return SubscriptionsResourceWithStreamingResponse(self._events.subscriptions) @@ -104,5 +104,5 @@ def __init__(self, events: AsyncEventsResource) -> None: @cached_property def subscriptions(self) -> AsyncSubscriptionsResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" return AsyncSubscriptionsResourceWithStreamingResponse(self._events.subscriptions) diff --git a/src/casedev/resources/vault/events/subscriptions.py b/src/casedev/resources/vault/events/subscriptions.py index 8dd48cdd..22d1a550 100644 --- a/src/casedev/resources/vault/events/subscriptions.py +++ b/src/casedev/resources/vault/events/subscriptions.py @@ -23,7 +23,7 @@ class SubscriptionsResource(SyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" @cached_property def with_raw_response(self) -> SubscriptionsResourceWithRawResponse: @@ -301,7 +301,7 @@ def test( class AsyncSubscriptionsResource(AsyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped event subscriptions and delivery testing""" @cached_property def with_raw_response(self) -> AsyncSubscriptionsResourceWithRawResponse: diff --git a/src/casedev/resources/vault/memory.py b/src/casedev/resources/vault/memory.py index 96f66bc5..051458a5 100644 --- a/src/casedev/resources/vault/memory.py +++ b/src/casedev/resources/vault/memory.py @@ -27,7 +27,7 @@ class MemoryResource(SyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" @cached_property def with_raw_response(self) -> MemoryResourceWithRawResponse: @@ -261,7 +261,7 @@ def search( class AsyncMemoryResource(AsyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" @cached_property def with_raw_response(self) -> AsyncMemoryResourceWithRawResponse: diff --git a/src/casedev/resources/vault/multipart.py b/src/casedev/resources/vault/multipart.py index 04a8989a..208a0c44 100644 --- a/src/casedev/resources/vault/multipart.py +++ b/src/casedev/resources/vault/multipart.py @@ -6,7 +6,7 @@ import httpx -from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -16,8 +16,14 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...types.vault import multipart_abort_params, multipart_get_part_urls_params +from ...types.vault import ( + multipart_init_params, + multipart_abort_params, + multipart_complete_params, + multipart_get_part_urls_params, +) from ..._base_client import make_request_options +from ...types.vault.multipart_init_response import MultipartInitResponse from ...types.vault.multipart_get_part_urls_response import MultipartGetPartURLsResponse __all__ = ["MultipartResource", "AsyncMultipartResource"] @@ -92,6 +98,58 @@ def abort( cast_to=NoneType, ) + def complete( + self, + id: str, + *, + object_id: str, + parts: Iterable[multipart_complete_params.Part], + size_bytes: int, + upload_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, + ) -> None: + """ + Complete a multipart upload by providing the list of part numbers and ETags + (live). Single PUT uploads are capped at 5GB; multipart default max is 16GB + (configurable). + + Args: + size_bytes: File size in bytes (default max 16GB). Configure via + VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template("/vault/{id}/multipart/complete", id=id), + body=maybe_transform( + { + "object_id": object_id, + "parts": parts, + "size_bytes": size_bytes, + "upload_id": upload_id, + }, + multipart_complete_params.MultipartCompleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + def get_part_urls( self, id: str, @@ -142,6 +200,83 @@ def get_part_urls( cast_to=MultipartGetPartURLsResponse, ) + def init( + self, + id: str, + *, + content_type: str, + filename: str, + size_bytes: int, + auto_index: bool | Omit = omit, + is_ai_generated: bool | Omit = omit, + metadata: object | Omit = omit, + part_size_bytes: int | Omit = omit, + path: 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, + ) -> MultipartInitResponse: + """Initiate a multipart upload for large files (>5GB). + + Single PUT uploads are + capped at 5GB; multipart default max is 16GB (configurable). Multipart uploads + are supported in production. Returns an uploadId and object metadata. Use part + URLs endpoint to upload parts and complete endpoint to finalize. + + Args: + content_type: MIME type of the file + + filename: Name of the file to upload + + size_bytes: File size in bytes (required, default max 16GB). Configure via + VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + + auto_index: Whether to automatically process and index the file for search + + is_ai_generated: Marks the file as AI-generated work product (e.g. uploaded by an agent) rather + than a user-provided source document. Persisted on the object and returned by + object listings so clients can distinguish provenance. + + metadata: Additional metadata to associate with the file + + part_size_bytes: Multipart part size in bytes (min 5MB, max 5GB). Defaults to 64MB. + + path: Optional folder path for hierarchy preservation + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/vault/{id}/multipart/init", id=id), + body=maybe_transform( + { + "content_type": content_type, + "filename": filename, + "size_bytes": size_bytes, + "auto_index": auto_index, + "is_ai_generated": is_ai_generated, + "metadata": metadata, + "part_size_bytes": part_size_bytes, + "path": path, + }, + multipart_init_params.MultipartInitParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MultipartInitResponse, + ) + class AsyncMultipartResource(AsyncAPIResource): """Secure document storage with semantic search and GraphRAG""" @@ -212,6 +347,58 @@ async def abort( cast_to=NoneType, ) + async def complete( + self, + id: str, + *, + object_id: str, + parts: Iterable[multipart_complete_params.Part], + size_bytes: int, + upload_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, + ) -> None: + """ + Complete a multipart upload by providing the list of part numbers and ETags + (live). Single PUT uploads are capped at 5GB; multipart default max is 16GB + (configurable). + + Args: + size_bytes: File size in bytes (default max 16GB). Configure via + VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template("/vault/{id}/multipart/complete", id=id), + body=await async_maybe_transform( + { + "object_id": object_id, + "parts": parts, + "size_bytes": size_bytes, + "upload_id": upload_id, + }, + multipart_complete_params.MultipartCompleteParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + async def get_part_urls( self, id: str, @@ -262,6 +449,83 @@ async def get_part_urls( cast_to=MultipartGetPartURLsResponse, ) + async def init( + self, + id: str, + *, + content_type: str, + filename: str, + size_bytes: int, + auto_index: bool | Omit = omit, + is_ai_generated: bool | Omit = omit, + metadata: object | Omit = omit, + part_size_bytes: int | Omit = omit, + path: 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, + ) -> MultipartInitResponse: + """Initiate a multipart upload for large files (>5GB). + + Single PUT uploads are + capped at 5GB; multipart default max is 16GB (configurable). Multipart uploads + are supported in production. Returns an uploadId and object metadata. Use part + URLs endpoint to upload parts and complete endpoint to finalize. + + Args: + content_type: MIME type of the file + + filename: Name of the file to upload + + size_bytes: File size in bytes (required, default max 16GB). Configure via + VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + + auto_index: Whether to automatically process and index the file for search + + is_ai_generated: Marks the file as AI-generated work product (e.g. uploaded by an agent) rather + than a user-provided source document. Persisted on the object and returned by + object listings so clients can distinguish provenance. + + metadata: Additional metadata to associate with the file + + part_size_bytes: Multipart part size in bytes (min 5MB, max 5GB). Defaults to 64MB. + + path: Optional folder path for hierarchy preservation + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/vault/{id}/multipart/init", id=id), + body=await async_maybe_transform( + { + "content_type": content_type, + "filename": filename, + "size_bytes": size_bytes, + "auto_index": auto_index, + "is_ai_generated": is_ai_generated, + "metadata": metadata, + "part_size_bytes": part_size_bytes, + "path": path, + }, + multipart_init_params.MultipartInitParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MultipartInitResponse, + ) + class MultipartResourceWithRawResponse: def __init__(self, multipart: MultipartResource) -> None: @@ -270,9 +534,15 @@ def __init__(self, multipart: MultipartResource) -> None: self.abort = to_raw_response_wrapper( multipart.abort, ) + self.complete = to_raw_response_wrapper( + multipart.complete, + ) self.get_part_urls = to_raw_response_wrapper( multipart.get_part_urls, ) + self.init = to_raw_response_wrapper( + multipart.init, + ) class AsyncMultipartResourceWithRawResponse: @@ -282,9 +552,15 @@ def __init__(self, multipart: AsyncMultipartResource) -> None: self.abort = async_to_raw_response_wrapper( multipart.abort, ) + self.complete = async_to_raw_response_wrapper( + multipart.complete, + ) self.get_part_urls = async_to_raw_response_wrapper( multipart.get_part_urls, ) + self.init = async_to_raw_response_wrapper( + multipart.init, + ) class MultipartResourceWithStreamingResponse: @@ -294,9 +570,15 @@ def __init__(self, multipart: MultipartResource) -> None: self.abort = to_streamed_response_wrapper( multipart.abort, ) + self.complete = to_streamed_response_wrapper( + multipart.complete, + ) self.get_part_urls = to_streamed_response_wrapper( multipart.get_part_urls, ) + self.init = to_streamed_response_wrapper( + multipart.init, + ) class AsyncMultipartResourceWithStreamingResponse: @@ -306,6 +588,12 @@ def __init__(self, multipart: AsyncMultipartResource) -> None: self.abort = async_to_streamed_response_wrapper( multipart.abort, ) + self.complete = async_to_streamed_response_wrapper( + multipart.complete, + ) self.get_part_urls = async_to_streamed_response_wrapper( multipart.get_part_urls, ) + self.init = async_to_streamed_response_wrapper( + multipart.init, + ) diff --git a/src/casedev/resources/vault/objects.py b/src/casedev/resources/vault/objects.py index 91c0f099..159a8f62 100644 --- a/src/casedev/resources/vault/objects.py +++ b/src/casedev/resources/vault/objects.py @@ -7,7 +7,7 @@ import httpx -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +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 @@ -26,6 +26,9 @@ async_to_custom_streamed_response_wrapper, ) from ...types.vault import ( + object_list_params, + object_merge_params, + object_append_params, object_delete_params, object_update_params, object_get_pages_params, @@ -35,6 +38,8 @@ ) from ..._base_client import make_request_options from ...types.vault.object_list_response import ObjectListResponse +from ...types.vault.object_merge_response import ObjectMergeResponse +from ...types.vault.object_append_response import ObjectAppendResponse from ...types.vault.object_delete_response import ObjectDeleteResponse from ...types.vault.object_update_response import ObjectUpdateResponse from ...types.vault.object_get_text_response import ObjectGetTextResponse @@ -42,14 +47,13 @@ from ...types.vault.object_get_pages_response import ObjectGetPagesResponse from ...types.vault.object_get_chunks_response import ObjectGetChunksResponse from ...types.vault.object_get_ocr_words_response import ObjectGetOcrWordsResponse -from ...types.vault.object_get_summarize_job_response import ObjectGetSummarizeJobResponse from ...types.vault.object_create_presigned_url_response import ObjectCreatePresignedURLResponse __all__ = ["ObjectsResource", "AsyncObjectsResource"] class ObjectsResource(SyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" @cached_property def with_raw_response(self) -> ObjectsResourceWithRawResponse: @@ -169,6 +173,7 @@ def list( self, id: str, *, + include_unconfirmed: bool | 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, @@ -181,6 +186,9 @@ def list( ingestion status, and processing statistics. Args: + include_unconfirmed: Include placeholders for uploads that were never completed (awaiting_upload) or + were cancelled (aborted). Excluded by default. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -194,7 +202,13 @@ def list( return self._get( path_template("/vault/{id}/objects", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"include_unconfirmed": include_unconfirmed}, object_list_params.ObjectListParams + ), ), cast_to=ObjectListResponse, ) @@ -244,6 +258,76 @@ def delete( cast_to=ObjectDeleteResponse, ) + def append( + self, + object_id: str, + *, + id: str, + append_object_ids: SequenceNotStr[str], + back_links: bool | Omit = omit, + back_links_text: str | Omit = omit, + bates: object_append_params.Bates | Omit = omit, + rewrite_links: bool | 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, + ) -> ObjectAppendResponse: + """ + Merges one or more PDF vault objects onto the end of an existing PDF vault + object, overwriting the target in place before returning. Optionally rewrites + citation links in the original target into internal PDF jumps and adds back + links on appended pages. The target object’s ingestion state is not affected; + appended pages are not searchable. + + Args: + append_object_ids: Vault object IDs whose pages will be appended onto the target object, in order. + Must not include the target object itself. + + back_links: Adds back links on appended pages + + back_links_text: Label text for the back link. Used only when backLinks is true and rendered + centered at the bottom of each appended page. + + bates: Optional Bates stamping for appended source PDFs. Numbering is deterministic + across appendObjectIds order and does not stamp the target report pages. + + rewrite_links: When true, rewrites links in the target object to internal PDF jumps when the + URL contains exactly one appended object ID as a standalone query parameter + value or decoded path segment. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not object_id: + raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") + return self._post( + path_template("/vault/{id}/objects/{object_id}/append", id=id, object_id=object_id), + body=maybe_transform( + { + "append_object_ids": append_object_ids, + "back_links": back_links, + "back_links_text": back_links_text, + "bates": bates, + "rewrite_links": rewrite_links, + }, + object_append_params.ObjectAppendParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ObjectAppendResponse, + ) + def create_presigned_url( self, object_id: str, @@ -529,21 +613,23 @@ def get_pages( cast_to=ObjectGetPagesResponse, ) - def get_summarize_job( + def get_text( self, - job_id: str, + object_id: str, *, id: str, - object_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, - ) -> ObjectGetSummarizeJobResponse: + ) -> ObjectGetTextResponse: """ - Get the status of a CaseMark summary workflow job. + Retrieves the full extracted text content from a processed vault object, + page-numbered (--- Page N --- markers) when the source document is paginated. + Useful for document review, analysis, or export. The object must have completed + processing before text can be retrieved. Args: extra_headers: Send extra headers @@ -558,37 +644,42 @@ def get_summarize_job( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") if not object_id: raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - if not job_id: - raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return self._get( - path_template( - "/vault/{id}/objects/{object_id}/summarize/{job_id}", id=id, object_id=object_id, job_id=job_id - ), + path_template("/vault/{id}/objects/{object_id}/text", id=id, object_id=object_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ObjectGetSummarizeJobResponse, + cast_to=ObjectGetTextResponse, ) - def get_text( + def merge( self, - object_id: str, - *, id: str, + *, + filename: str, + source_object_ids: SequenceNotStr[str], + source_rendition: Literal["original", "searchable_pdf"], + idempotency_key: str, + bates: object_merge_params.Bates | Omit = omit, + client_reference: 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, - ) -> ObjectGetTextResponse: - """Retrieves the full extracted text content from a processed vault object. + ) -> ObjectMergeResponse: + """Starts an asynchronous merge that creates a new PDF vault object. - Returns - the concatenated text from all chunks, useful for document review, analysis, or - export. The object must have completed processing before text can be retrieved. + Source objects + are unchanged. Missing searchable PDF renditions are generated on demand before + combining. Completion is reported through vault.object.merge webhooks. Args: + filename: Output PDF filename + + source_object_ids: Source object IDs in output order + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -599,19 +690,28 @@ def get_text( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not object_id: - raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - return self._get( - path_template("/vault/{id}/objects/{object_id}/text", id=id, object_id=object_id), + extra_headers = {"Idempotency-Key": idempotency_key, **(extra_headers or {})} + return self._post( + path_template("/vault/{id}/objects/merge", id=id), + body=maybe_transform( + { + "filename": filename, + "source_object_ids": source_object_ids, + "source_rendition": source_rendition, + "bates": bates, + "client_reference": client_reference, + }, + object_merge_params.ObjectMergeParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ObjectGetTextResponse, + cast_to=ObjectMergeResponse, ) class AsyncObjectsResource(AsyncAPIResource): - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" @cached_property def with_raw_response(self) -> AsyncObjectsResourceWithRawResponse: @@ -731,6 +831,7 @@ async def list( self, id: str, *, + include_unconfirmed: bool | 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, @@ -743,6 +844,9 @@ async def list( ingestion status, and processing statistics. Args: + include_unconfirmed: Include placeholders for uploads that were never completed (awaiting_upload) or + were cancelled (aborted). Excluded by default. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -756,7 +860,13 @@ async def list( return await self._get( path_template("/vault/{id}/objects", id=id), options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"include_unconfirmed": include_unconfirmed}, object_list_params.ObjectListParams + ), ), cast_to=ObjectListResponse, ) @@ -806,6 +916,76 @@ async def delete( cast_to=ObjectDeleteResponse, ) + async def append( + self, + object_id: str, + *, + id: str, + append_object_ids: SequenceNotStr[str], + back_links: bool | Omit = omit, + back_links_text: str | Omit = omit, + bates: object_append_params.Bates | Omit = omit, + rewrite_links: bool | 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, + ) -> ObjectAppendResponse: + """ + Merges one or more PDF vault objects onto the end of an existing PDF vault + object, overwriting the target in place before returning. Optionally rewrites + citation links in the original target into internal PDF jumps and adds back + links on appended pages. The target object’s ingestion state is not affected; + appended pages are not searchable. + + Args: + append_object_ids: Vault object IDs whose pages will be appended onto the target object, in order. + Must not include the target object itself. + + back_links: Adds back links on appended pages + + back_links_text: Label text for the back link. Used only when backLinks is true and rendered + centered at the bottom of each appended page. + + bates: Optional Bates stamping for appended source PDFs. Numbering is deterministic + across appendObjectIds order and does not stamp the target report pages. + + rewrite_links: When true, rewrites links in the target object to internal PDF jumps when the + URL contains exactly one appended object ID as a standalone query parameter + value or decoded path segment. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not object_id: + raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") + return await self._post( + path_template("/vault/{id}/objects/{object_id}/append", id=id, object_id=object_id), + body=await async_maybe_transform( + { + "append_object_ids": append_object_ids, + "back_links": back_links, + "back_links_text": back_links_text, + "bates": bates, + "rewrite_links": rewrite_links, + }, + object_append_params.ObjectAppendParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ObjectAppendResponse, + ) + async def create_presigned_url( self, object_id: str, @@ -1091,21 +1271,23 @@ async def get_pages( cast_to=ObjectGetPagesResponse, ) - async def get_summarize_job( + async def get_text( self, - job_id: str, + object_id: str, *, id: str, - object_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, - ) -> ObjectGetSummarizeJobResponse: + ) -> ObjectGetTextResponse: """ - Get the status of a CaseMark summary workflow job. + Retrieves the full extracted text content from a processed vault object, + page-numbered (--- Page N --- markers) when the source document is paginated. + Useful for document review, analysis, or export. The object must have completed + processing before text can be retrieved. Args: extra_headers: Send extra headers @@ -1120,37 +1302,42 @@ async def get_summarize_job( raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") if not object_id: raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - if not job_id: - raise ValueError(f"Expected a non-empty value for `job_id` but received {job_id!r}") return await self._get( - path_template( - "/vault/{id}/objects/{object_id}/summarize/{job_id}", id=id, object_id=object_id, job_id=job_id - ), + path_template("/vault/{id}/objects/{object_id}/text", id=id, object_id=object_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ObjectGetSummarizeJobResponse, + cast_to=ObjectGetTextResponse, ) - async def get_text( + async def merge( self, - object_id: str, - *, id: str, + *, + filename: str, + source_object_ids: SequenceNotStr[str], + source_rendition: Literal["original", "searchable_pdf"], + idempotency_key: str, + bates: object_merge_params.Bates | Omit = omit, + client_reference: 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, - ) -> ObjectGetTextResponse: - """Retrieves the full extracted text content from a processed vault object. + ) -> ObjectMergeResponse: + """Starts an asynchronous merge that creates a new PDF vault object. - Returns - the concatenated text from all chunks, useful for document review, analysis, or - export. The object must have completed processing before text can be retrieved. + Source objects + are unchanged. Missing searchable PDF renditions are generated on demand before + combining. Completion is reported through vault.object.merge webhooks. Args: + filename: Output PDF filename + + source_object_ids: Source object IDs in output order + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1161,14 +1348,23 @@ async def get_text( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - if not object_id: - raise ValueError(f"Expected a non-empty value for `object_id` but received {object_id!r}") - return await self._get( - path_template("/vault/{id}/objects/{object_id}/text", id=id, object_id=object_id), + extra_headers = {"Idempotency-Key": idempotency_key, **(extra_headers or {})} + return await self._post( + path_template("/vault/{id}/objects/merge", id=id), + body=await async_maybe_transform( + { + "filename": filename, + "source_object_ids": source_object_ids, + "source_rendition": source_rendition, + "bates": bates, + "client_reference": client_reference, + }, + object_merge_params.ObjectMergeParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=ObjectGetTextResponse, + cast_to=ObjectMergeResponse, ) @@ -1188,6 +1384,9 @@ def __init__(self, objects: ObjectsResource) -> None: self.delete = to_raw_response_wrapper( objects.delete, ) + self.append = to_raw_response_wrapper( + objects.append, + ) self.create_presigned_url = to_raw_response_wrapper( objects.create_presigned_url, ) @@ -1204,12 +1403,12 @@ def __init__(self, objects: ObjectsResource) -> None: self.get_pages = to_raw_response_wrapper( objects.get_pages, ) - self.get_summarize_job = to_raw_response_wrapper( - objects.get_summarize_job, - ) self.get_text = to_raw_response_wrapper( objects.get_text, ) + self.merge = to_raw_response_wrapper( + objects.merge, + ) class AsyncObjectsResourceWithRawResponse: @@ -1228,6 +1427,9 @@ def __init__(self, objects: AsyncObjectsResource) -> None: self.delete = async_to_raw_response_wrapper( objects.delete, ) + self.append = async_to_raw_response_wrapper( + objects.append, + ) self.create_presigned_url = async_to_raw_response_wrapper( objects.create_presigned_url, ) @@ -1244,12 +1446,12 @@ def __init__(self, objects: AsyncObjectsResource) -> None: self.get_pages = async_to_raw_response_wrapper( objects.get_pages, ) - self.get_summarize_job = async_to_raw_response_wrapper( - objects.get_summarize_job, - ) self.get_text = async_to_raw_response_wrapper( objects.get_text, ) + self.merge = async_to_raw_response_wrapper( + objects.merge, + ) class ObjectsResourceWithStreamingResponse: @@ -1268,6 +1470,9 @@ def __init__(self, objects: ObjectsResource) -> None: self.delete = to_streamed_response_wrapper( objects.delete, ) + self.append = to_streamed_response_wrapper( + objects.append, + ) self.create_presigned_url = to_streamed_response_wrapper( objects.create_presigned_url, ) @@ -1284,12 +1489,12 @@ def __init__(self, objects: ObjectsResource) -> None: self.get_pages = to_streamed_response_wrapper( objects.get_pages, ) - self.get_summarize_job = to_streamed_response_wrapper( - objects.get_summarize_job, - ) self.get_text = to_streamed_response_wrapper( objects.get_text, ) + self.merge = to_streamed_response_wrapper( + objects.merge, + ) class AsyncObjectsResourceWithStreamingResponse: @@ -1308,6 +1513,9 @@ def __init__(self, objects: AsyncObjectsResource) -> None: self.delete = async_to_streamed_response_wrapper( objects.delete, ) + self.append = async_to_streamed_response_wrapper( + objects.append, + ) self.create_presigned_url = async_to_streamed_response_wrapper( objects.create_presigned_url, ) @@ -1324,9 +1532,9 @@ def __init__(self, objects: AsyncObjectsResource) -> None: self.get_pages = async_to_streamed_response_wrapper( objects.get_pages, ) - self.get_summarize_job = async_to_streamed_response_wrapper( - objects.get_summarize_job, - ) self.get_text = async_to_streamed_response_wrapper( objects.get_text, ) + self.merge = async_to_streamed_response_wrapper( + objects.merge, + ) diff --git a/src/casedev/resources/vault/vault.py b/src/casedev/resources/vault/vault.py index cd252ba8..3298dd52 100644 --- a/src/casedev/resources/vault/vault.py +++ b/src/casedev/resources/vault/vault.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, overload +from typing_extensions import Literal import httpx @@ -40,15 +40,7 @@ AsyncObjectsResourceWithStreamingResponse, ) from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import path_template, required_args, maybe_transform, async_maybe_transform -from .graphrag import ( - GraphragResource, - AsyncGraphragResource, - GraphragResourceWithRawResponse, - AsyncGraphragResourceWithRawResponse, - GraphragResourceWithStreamingResponse, - AsyncGraphragResourceWithStreamingResponse, -) +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from .multipart import ( MultipartResource, @@ -94,11 +86,6 @@ class VaultResource(SyncAPIResource): def events(self) -> EventsResource: return EventsResource(self._client) - @cached_property - def graphrag(self) -> GraphragResource: - """Secure document storage with semantic search and GraphRAG""" - return GraphragResource(self._client) - @cached_property def groups(self) -> GroupsResource: """Secure document storage with semantic search and GraphRAG""" @@ -111,12 +98,12 @@ def multipart(self) -> MultipartResource: @cached_property def objects(self) -> ObjectsResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return ObjectsResource(self._client) @cached_property def memory(self) -> MemoryResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return MemoryResource(self._client) @cached_property @@ -383,15 +370,17 @@ def delete( cast_to=VaultDeleteResponse, ) - @overload def confirm_upload( self, object_id: str, *, id: str, - size_bytes: int, - success: Literal[True], + success: bool, + auto_ingest: bool | Omit = omit, + error_code: str | Omit = omit, + error_message: str | Omit = omit, etag: str | Omit = omit, + size_bytes: 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, @@ -403,53 +392,26 @@ def confirm_upload( This endpoint emits vault.upload.completed or vault.upload.failed events and is idempotent for - repeated confirmations. + repeated confirmations. Conditional fields: when success=true, sizeBytes is + required; when success=false, errorCode and errorMessage are required. These + rules are enforced server-side with specific 400 responses. Args: - size_bytes: Uploaded file size in bytes - success: Whether the upload succeeded - etag: S3 ETag for the uploaded object (optional if client cannot access ETag header) + auto_ingest: When true and the object was uploaded with auto_index, trigger ingestion + immediately after a successful confirmation (no separate ingest call needed). + The ingest outcome is reported in the `ingest` response field; an ingest failure + does not fail the confirmation. - extra_headers: Send extra headers + error_code: Client-side error code. Required when success=false. - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request + error_message: Client-side error message. Required when success=false. - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def confirm_upload( - self, - object_id: str, - *, - id: str, - error_code: str, - error_message: str, - success: Literal[False], - # 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, - ) -> VaultConfirmUploadResponse: - """Confirm whether a direct-to-S3 vault upload succeeded or failed. - - This endpoint - emits vault.upload.completed or vault.upload.failed events and is idempotent for - repeated confirmations. - - Args: - error_code: Client-side error code + etag: S3 ETag for the uploaded object (optional if client cannot access ETag header). + Only meaningful when success=true. - error_message: Client-side error message - - success: Whether the upload succeeded + size_bytes: Uploaded file size in bytes. Required when success=true. extra_headers: Send extra headers @@ -459,26 +421,6 @@ def confirm_upload( timeout: Override the client-level default timeout for this request, in seconds """ - ... - - @required_args(["id", "size_bytes", "success"], ["id", "error_code", "error_message", "success"]) - def confirm_upload( - self, - object_id: str, - *, - id: str, - size_bytes: int | Omit = omit, - success: Literal[True] | Literal[False], - etag: str | Omit = omit, - error_code: str | Omit = omit, - error_message: 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, - ) -> VaultConfirmUploadResponse: if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") if not object_id: @@ -487,11 +429,12 @@ def confirm_upload( path_template("/vault/{id}/upload/{object_id}/confirm", id=id, object_id=object_id), body=maybe_transform( { - "size_bytes": size_bytes, "success": success, - "etag": etag, + "auto_ingest": auto_ingest, "error_code": error_code, "error_message": error_message, + "etag": etag, + "size_bytes": size_bytes, }, vault_confirm_upload_params.VaultConfirmUploadParams, ), @@ -515,14 +458,13 @@ def ingest( ) -> VaultIngestResponse: """ Triggers ingestion workflow for a vault object to extract text, generate chunks, - and create embeddings. For supported file types (PDF, DOCX, PPTX, TXT, RTF, XML, - HTML, Markdown, CSV/TSV, JSON/YAML/TOML, common source code files, ZIP, audio, - video), processing happens asynchronously. ZIP archives are unpacked recursively - up to 5 levels, and each extracted file is created as an independent vault - object and ingested via the normal pipeline. For unsupported types (images, - etc.), the file is marked as completed immediately without text extraction. - GraphRAG indexing must be triggered separately via POST - /vault/:id/graphrag/:objectId. + and create embeddings. For supported file types (PDF, DOCX, PPTX, XLSX, TXT, + RTF, XML, HTML, Markdown, CSV/TSV, JSON/YAML/TOML, common source code files, + ZIP, audio, video), processing happens asynchronously. ZIP archives are unpacked + recursively up to 5 levels, and each extracted file is created as an independent + vault object and ingested via the normal pipeline. For unsupported types + (images, etc.), the file is marked as completed immediately without text + extraction. Args: extra_headers: Send extra headers @@ -611,9 +553,11 @@ def upload( content_type: str, filename: str, auto_index: bool | Omit = omit, + is_ai_generated: bool | Omit = omit, metadata: object | Omit = omit, path: str | Omit = omit, size_bytes: int | Omit = omit, + idempotency_key: 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, @@ -633,6 +577,10 @@ def upload( auto_index: Whether to automatically process and index the file for search + is_ai_generated: Marks the file as AI-generated work product (e.g. uploaded by an agent) rather + than a user-provided source document. Persisted on the object and returned by + object listings so clients can distinguish provenance. + metadata: Additional metadata to associate with the file path: Optional folder path for hierarchy preservation. Allows integrations to maintain @@ -652,6 +600,7 @@ def upload( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} return self._post( path_template("/vault/{id}/upload", id=id), body=maybe_transform( @@ -659,6 +608,7 @@ def upload( "content_type": content_type, "filename": filename, "auto_index": auto_index, + "is_ai_generated": is_ai_generated, "metadata": metadata, "path": path, "size_bytes": size_bytes, @@ -679,11 +629,6 @@ class AsyncVaultResource(AsyncAPIResource): def events(self) -> AsyncEventsResource: return AsyncEventsResource(self._client) - @cached_property - def graphrag(self) -> AsyncGraphragResource: - """Secure document storage with semantic search and GraphRAG""" - return AsyncGraphragResource(self._client) - @cached_property def groups(self) -> AsyncGroupsResource: """Secure document storage with semantic search and GraphRAG""" @@ -696,12 +641,12 @@ def multipart(self) -> AsyncMultipartResource: @cached_property def objects(self) -> AsyncObjectsResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return AsyncObjectsResource(self._client) @cached_property def memory(self) -> AsyncMemoryResource: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return AsyncMemoryResource(self._client) @cached_property @@ -968,15 +913,17 @@ async def delete( cast_to=VaultDeleteResponse, ) - @overload async def confirm_upload( self, object_id: str, *, id: str, - size_bytes: int, - success: Literal[True], + success: bool, + auto_ingest: bool | Omit = omit, + error_code: str | Omit = omit, + error_message: str | Omit = omit, etag: str | Omit = omit, + size_bytes: 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, @@ -988,53 +935,26 @@ async def confirm_upload( This endpoint emits vault.upload.completed or vault.upload.failed events and is idempotent for - repeated confirmations. + repeated confirmations. Conditional fields: when success=true, sizeBytes is + required; when success=false, errorCode and errorMessage are required. These + rules are enforced server-side with specific 400 responses. Args: - size_bytes: Uploaded file size in bytes - success: Whether the upload succeeded - etag: S3 ETag for the uploaded object (optional if client cannot access ETag header) + auto_ingest: When true and the object was uploaded with auto_index, trigger ingestion + immediately after a successful confirmation (no separate ingest call needed). + The ingest outcome is reported in the `ingest` response field; an ingest failure + does not fail the confirmation. - extra_headers: Send extra headers + error_code: Client-side error code. Required when success=false. - 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 - """ - ... - - @overload - async def confirm_upload( - self, - object_id: str, - *, - id: str, - error_code: str, - error_message: str, - success: Literal[False], - # 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, - ) -> VaultConfirmUploadResponse: - """Confirm whether a direct-to-S3 vault upload succeeded or failed. + error_message: Client-side error message. Required when success=false. - This endpoint - emits vault.upload.completed or vault.upload.failed events and is idempotent for - repeated confirmations. + etag: S3 ETag for the uploaded object (optional if client cannot access ETag header). + Only meaningful when success=true. - Args: - error_code: Client-side error code - - error_message: Client-side error message - - success: Whether the upload succeeded + size_bytes: Uploaded file size in bytes. Required when success=true. extra_headers: Send extra headers @@ -1044,26 +964,6 @@ async def confirm_upload( timeout: Override the client-level default timeout for this request, in seconds """ - ... - - @required_args(["id", "size_bytes", "success"], ["id", "error_code", "error_message", "success"]) - async def confirm_upload( - self, - object_id: str, - *, - id: str, - size_bytes: int | Omit = omit, - success: Literal[True] | Literal[False], - etag: str | Omit = omit, - error_code: str | Omit = omit, - error_message: 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, - ) -> VaultConfirmUploadResponse: if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") if not object_id: @@ -1072,11 +972,12 @@ async def confirm_upload( path_template("/vault/{id}/upload/{object_id}/confirm", id=id, object_id=object_id), body=await async_maybe_transform( { - "size_bytes": size_bytes, "success": success, - "etag": etag, + "auto_ingest": auto_ingest, "error_code": error_code, "error_message": error_message, + "etag": etag, + "size_bytes": size_bytes, }, vault_confirm_upload_params.VaultConfirmUploadParams, ), @@ -1100,14 +1001,13 @@ async def ingest( ) -> VaultIngestResponse: """ Triggers ingestion workflow for a vault object to extract text, generate chunks, - and create embeddings. For supported file types (PDF, DOCX, PPTX, TXT, RTF, XML, - HTML, Markdown, CSV/TSV, JSON/YAML/TOML, common source code files, ZIP, audio, - video), processing happens asynchronously. ZIP archives are unpacked recursively - up to 5 levels, and each extracted file is created as an independent vault - object and ingested via the normal pipeline. For unsupported types (images, - etc.), the file is marked as completed immediately without text extraction. - GraphRAG indexing must be triggered separately via POST - /vault/:id/graphrag/:objectId. + and create embeddings. For supported file types (PDF, DOCX, PPTX, XLSX, TXT, + RTF, XML, HTML, Markdown, CSV/TSV, JSON/YAML/TOML, common source code files, + ZIP, audio, video), processing happens asynchronously. ZIP archives are unpacked + recursively up to 5 levels, and each extracted file is created as an independent + vault object and ingested via the normal pipeline. For unsupported types + (images, etc.), the file is marked as completed immediately without text + extraction. Args: extra_headers: Send extra headers @@ -1196,9 +1096,11 @@ async def upload( content_type: str, filename: str, auto_index: bool | Omit = omit, + is_ai_generated: bool | Omit = omit, metadata: object | Omit = omit, path: str | Omit = omit, size_bytes: int | Omit = omit, + idempotency_key: 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, @@ -1218,6 +1120,10 @@ async def upload( auto_index: Whether to automatically process and index the file for search + is_ai_generated: Marks the file as AI-generated work product (e.g. uploaded by an agent) rather + than a user-provided source document. Persisted on the object and returned by + object listings so clients can distinguish provenance. + metadata: Additional metadata to associate with the file path: Optional folder path for hierarchy preservation. Allows integrations to maintain @@ -1237,6 +1143,7 @@ async def upload( """ if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} return await self._post( path_template("/vault/{id}/upload", id=id), body=await async_maybe_transform( @@ -1244,6 +1151,7 @@ async def upload( "content_type": content_type, "filename": filename, "auto_index": auto_index, + "is_ai_generated": is_ai_generated, "metadata": metadata, "path": path, "size_bytes": size_bytes, @@ -1293,11 +1201,6 @@ def __init__(self, vault: VaultResource) -> None: def events(self) -> EventsResourceWithRawResponse: return EventsResourceWithRawResponse(self._vault.events) - @cached_property - def graphrag(self) -> GraphragResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" - return GraphragResourceWithRawResponse(self._vault.graphrag) - @cached_property def groups(self) -> GroupsResourceWithRawResponse: """Secure document storage with semantic search and GraphRAG""" @@ -1310,12 +1213,12 @@ def multipart(self) -> MultipartResourceWithRawResponse: @cached_property def objects(self) -> ObjectsResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return ObjectsResourceWithRawResponse(self._vault.objects) @cached_property def memory(self) -> MemoryResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return MemoryResourceWithRawResponse(self._vault.memory) @@ -1355,11 +1258,6 @@ def __init__(self, vault: AsyncVaultResource) -> None: def events(self) -> AsyncEventsResourceWithRawResponse: return AsyncEventsResourceWithRawResponse(self._vault.events) - @cached_property - def graphrag(self) -> AsyncGraphragResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" - return AsyncGraphragResourceWithRawResponse(self._vault.graphrag) - @cached_property def groups(self) -> AsyncGroupsResourceWithRawResponse: """Secure document storage with semantic search and GraphRAG""" @@ -1372,12 +1270,12 @@ def multipart(self) -> AsyncMultipartResourceWithRawResponse: @cached_property def objects(self) -> AsyncObjectsResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return AsyncObjectsResourceWithRawResponse(self._vault.objects) @cached_property def memory(self) -> AsyncMemoryResourceWithRawResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return AsyncMemoryResourceWithRawResponse(self._vault.memory) @@ -1417,11 +1315,6 @@ def __init__(self, vault: VaultResource) -> None: def events(self) -> EventsResourceWithStreamingResponse: return EventsResourceWithStreamingResponse(self._vault.events) - @cached_property - def graphrag(self) -> GraphragResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" - return GraphragResourceWithStreamingResponse(self._vault.graphrag) - @cached_property def groups(self) -> GroupsResourceWithStreamingResponse: """Secure document storage with semantic search and GraphRAG""" @@ -1434,12 +1327,12 @@ def multipart(self) -> MultipartResourceWithStreamingResponse: @cached_property def objects(self) -> ObjectsResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return ObjectsResourceWithStreamingResponse(self._vault.objects) @cached_property def memory(self) -> MemoryResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return MemoryResourceWithStreamingResponse(self._vault.memory) @@ -1479,11 +1372,6 @@ def __init__(self, vault: AsyncVaultResource) -> None: def events(self) -> AsyncEventsResourceWithStreamingResponse: return AsyncEventsResourceWithStreamingResponse(self._vault.events) - @cached_property - def graphrag(self) -> AsyncGraphragResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" - return AsyncGraphragResourceWithStreamingResponse(self._vault.graphrag) - @cached_property def groups(self) -> AsyncGroupsResourceWithStreamingResponse: """Secure document storage with semantic search and GraphRAG""" @@ -1496,10 +1384,10 @@ def multipart(self) -> AsyncMultipartResourceWithStreamingResponse: @cached_property def objects(self) -> AsyncObjectsResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault object management, content access, and document operations""" return AsyncObjectsResourceWithStreamingResponse(self._vault.objects) @cached_property def memory(self) -> AsyncMemoryResourceWithStreamingResponse: - """Secure document storage with semantic search and GraphRAG""" + """Vault-scoped persistent memory and semantic retrieval""" return AsyncMemoryResourceWithStreamingResponse(self._vault.memory) diff --git a/src/casedev/resources/voice/transcription.py b/src/casedev/resources/voice/transcription.py index b59a94e1..5abd518d 100644 --- a/src/casedev/resources/voice/transcription.py +++ b/src/casedev/resources/voice/transcription.py @@ -71,13 +71,15 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionCreateResponse: - """Creates an asynchronous transcription job for audio files. + """Creates an asynchronous transcription job for audio or video files. - Supports two modes: + Supports two + modes: **Vault-based (recommended)**: Pass `vault_id` and `object_id` to transcribe - audio from your vault. The transcript will automatically be saved back to the - vault when complete. + media from your vault. Large videos are converted to an internal MP3 derivative + before transcription while the original video remains the transcript source. The + transcript is automatically saved back to the vault when complete. **Direct URL (legacy)**: Pass `audio_url` for direct transcription without automatic storage. @@ -280,13 +282,15 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranscriptionCreateResponse: - """Creates an asynchronous transcription job for audio files. + """Creates an asynchronous transcription job for audio or video files. - Supports two modes: + Supports two + modes: **Vault-based (recommended)**: Pass `vault_id` and `object_id` to transcribe - audio from your vault. The transcript will automatically be saved back to the - vault when complete. + media from your vault. Large videos are converted to an internal MP3 derivative + before transcription while the original video remains the transcript source. The + transcript is automatically saved back to the vault when complete. **Direct URL (legacy)**: Pass `audio_url` for direct transcription without automatic storage. diff --git a/src/casedev/types/agent/v1/__init__.py b/src/casedev/types/agent/v1/__init__.py deleted file mode 100644 index 0945cf54..00000000 --- a/src/casedev/types/agent/v1/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .run_list_params import RunListParams as RunListParams -from .run_watch_params import RunWatchParams as RunWatchParams -from .agent_list_params import AgentListParams as AgentListParams -from .run_create_params import RunCreateParams as RunCreateParams -from .run_events_params import RunEventsParams as RunEventsParams -from .run_exec_response import RunExecResponse as RunExecResponse -from .run_list_response import RunListResponse as RunListResponse -from .run_watch_response import RunWatchResponse as RunWatchResponse -from .agent_create_params import AgentCreateParams as AgentCreateParams -from .agent_list_response import AgentListResponse as AgentListResponse -from .agent_update_params import AgentUpdateParams as AgentUpdateParams -from .run_cancel_response import RunCancelResponse as RunCancelResponse -from .run_create_response import RunCreateResponse as RunCreateResponse -from .run_events_response import RunEventsResponse as RunEventsResponse -from .agent_create_response import AgentCreateResponse as AgentCreateResponse -from .agent_delete_response import AgentDeleteResponse as AgentDeleteResponse -from .agent_update_response import AgentUpdateResponse as AgentUpdateResponse -from .execute_create_params import ExecuteCreateParams as ExecuteCreateParams -from .agent_retrieve_response import AgentRetrieveResponse as AgentRetrieveResponse -from .execute_create_response import ExecuteCreateResponse as ExecuteCreateResponse -from .run_get_status_response import RunGetStatusResponse as RunGetStatusResponse -from .run_get_details_response import RunGetDetailsResponse as RunGetDetailsResponse diff --git a/src/casedev/types/agent/v1/agent_create_params.py b/src/casedev/types/agent/v1/agent_create_params.py deleted file mode 100644 index 35829b58..00000000 --- a/src/casedev/types/agent/v1/agent_create_params.py +++ /dev/null @@ -1,59 +0,0 @@ -# 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, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo - -__all__ = ["AgentCreateParams", "Sandbox"] - - -class AgentCreateParams(TypedDict, total=False): - instructions: Required[str] - """System instructions that define agent behavior""" - - name: Required[str] - """Display name for the agent""" - - description: str - """Optional description of the agent""" - - disabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="disabledTools")] - """Denylist of tools the agent cannot use. - - Mutually exclusive with enabledTools — set one or the other, not both. - """ - - enabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="enabledTools")] - """Allowlist of tools the agent can use. - - Mutually exclusive with disabledTools — set one or the other, not both. - """ - - model: str - """LLM model identifier (e.g. - - anthropic/claude-sonnet-4.6). Defaults to anthropic/claude-sonnet-4.6 - """ - - sandbox: Optional[Sandbox] - """Custom sandbox configuration (cpu, memoryMiB)""" - - vault_groups: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultGroups")] - """Restrict agent to vaults within specific vault group IDs""" - - vault_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultIds")] - """Restrict agent to specific vault IDs""" - - -class Sandbox(TypedDict, total=False): - """Custom sandbox configuration (cpu, memoryMiB)""" - - cpu: int - """Number of CPUs""" - - memory_mi_b: Annotated[int, PropertyInfo(alias="memoryMiB")] - """Memory in MiB""" diff --git a/src/casedev/types/agent/v1/agent_create_response.py b/src/casedev/types/agent/v1/agent_create_response.py deleted file mode 100644 index e905bb0c..00000000 --- a/src/casedev/types/agent/v1/agent_create_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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["AgentCreateResponse"] - - -class AgentCreateResponse(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - description: Optional[str] = None - - disabled_tools: Optional[List[str]] = FieldInfo(alias="disabledTools", default=None) - - enabled_tools: Optional[List[str]] = FieldInfo(alias="enabledTools", default=None) - - instructions: Optional[str] = None - - model: Optional[str] = None - - name: Optional[str] = None - - sandbox: Optional[object] = None - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - vault_ids: Optional[List[str]] = FieldInfo(alias="vaultIds", default=None) diff --git a/src/casedev/types/agent/v1/agent_delete_response.py b/src/casedev/types/agent/v1/agent_delete_response.py deleted file mode 100644 index 148d8f52..00000000 --- a/src/casedev/types/agent/v1/agent_delete_response.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ...._models import BaseModel - -__all__ = ["AgentDeleteResponse"] - - -class AgentDeleteResponse(BaseModel): - ok: Optional[bool] = None diff --git a/src/casedev/types/agent/v1/agent_list_params.py b/src/casedev/types/agent/v1/agent_list_params.py deleted file mode 100644 index f41fc45d..00000000 --- a/src/casedev/types/agent/v1/agent_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["AgentListParams"] - - -class AgentListParams(TypedDict, total=False): - cursor: str - """Pagination cursor (agent ID from previous page). - - Returns agents created before this agent. - """ - - limit: int - """Maximum number of agents to return (default 50, max 250)""" diff --git a/src/casedev/types/agent/v1/agent_list_response.py b/src/casedev/types/agent/v1/agent_list_response.py deleted file mode 100644 index cba2c4b1..00000000 --- a/src/casedev/types/agent/v1/agent_list_response.py +++ /dev/null @@ -1,37 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["AgentListResponse", "Agent"] - - -class Agent(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - description: Optional[str] = None - - is_active: Optional[bool] = FieldInfo(alias="isActive", default=None) - - model: Optional[str] = None - - name: Optional[str] = None - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - vault_ids: Optional[List[str]] = FieldInfo(alias="vaultIds", default=None) - - -class AgentListResponse(BaseModel): - agents: Optional[List[Agent]] = None - - has_more: Optional[bool] = FieldInfo(alias="hasMore", default=None) - - next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None) - """Pass as cursor to fetch the next page""" diff --git a/src/casedev/types/agent/v1/agent_retrieve_response.py b/src/casedev/types/agent/v1/agent_retrieve_response.py deleted file mode 100644 index 4c8fc445..00000000 --- a/src/casedev/types/agent/v1/agent_retrieve_response.py +++ /dev/null @@ -1,36 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["AgentRetrieveResponse"] - - -class AgentRetrieveResponse(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - description: Optional[str] = None - - disabled_tools: Optional[List[str]] = FieldInfo(alias="disabledTools", default=None) - - enabled_tools: Optional[List[str]] = FieldInfo(alias="enabledTools", default=None) - - instructions: Optional[str] = None - - is_active: Optional[bool] = FieldInfo(alias="isActive", default=None) - - model: Optional[str] = None - - name: Optional[str] = None - - sandbox: Optional[object] = None - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - vault_ids: Optional[List[str]] = FieldInfo(alias="vaultIds", default=None) diff --git a/src/casedev/types/agent/v1/agent_update_params.py b/src/casedev/types/agent/v1/agent_update_params.py deleted file mode 100644 index 5084402d..00000000 --- a/src/casedev/types/agent/v1/agent_update_params.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo - -__all__ = ["AgentUpdateParams"] - - -class AgentUpdateParams(TypedDict, total=False): - description: Optional[str] - """Updated agent description. Pass null to clear if supported by the client.""" - - disabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="disabledTools")] - """Denylist of tools the agent cannot use. - - Mutually exclusive with enabledTools — set one or the other, not both. Pass null - to clear. - """ - - enabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="enabledTools")] - """Allowlist of tools the agent can use. - - Mutually exclusive with disabledTools — set one or the other, not both. Pass - null to clear. - """ - - instructions: str - """Updated system instructions that guide agent behavior""" - - model: str - """Model identifier the agent should use for future runs""" - - name: str - """Updated agent display name""" - - sandbox: Optional[object] - """Sandbox configuration override for future agent runs. Pass null to clear.""" - - vault_groups: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultGroups")] - """Vault group IDs the agent can access. Pass null to clear.""" - - vault_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultIds")] - """Vault IDs the agent can access directly. Pass null to clear.""" diff --git a/src/casedev/types/agent/v1/agent_update_response.py b/src/casedev/types/agent/v1/agent_update_response.py deleted file mode 100644 index 8f6ddb17..00000000 --- a/src/casedev/types/agent/v1/agent_update_response.py +++ /dev/null @@ -1,38 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["AgentUpdateResponse"] - - -class AgentUpdateResponse(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - description: Optional[str] = None - - disabled_tools: Optional[List[str]] = FieldInfo(alias="disabledTools", default=None) - - enabled_tools: Optional[List[str]] = FieldInfo(alias="enabledTools", default=None) - - instructions: Optional[str] = None - - is_active: Optional[bool] = FieldInfo(alias="isActive", default=None) - - model: Optional[str] = None - - name: Optional[str] = None - - sandbox: Optional[object] = None - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - vault_groups: Optional[List[str]] = FieldInfo(alias="vaultGroups", default=None) - - vault_ids: Optional[List[str]] = FieldInfo(alias="vaultIds", default=None) diff --git a/src/casedev/types/agent/v1/execute_create_params.py b/src/casedev/types/agent/v1/execute_create_params.py deleted file mode 100644 index de00ee22..00000000 --- a/src/casedev/types/agent/v1/execute_create_params.py +++ /dev/null @@ -1,62 +0,0 @@ -# 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, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo - -__all__ = ["ExecuteCreateParams", "Sandbox"] - - -class ExecuteCreateParams(TypedDict, total=False): - prompt: Required[str] - """Task prompt for the agent""" - - disabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="disabledTools")] - """Denylist of tools the agent cannot use. - - Mutually exclusive with enabledTools — set one or the other, not both. - """ - - enabled_tools: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="enabledTools")] - """Allowlist of tools the agent can use. - - Mutually exclusive with disabledTools — set one or the other, not both. - """ - - guidance: Optional[str] - """Additional context or constraints for this run""" - - instructions: str - """System instructions. - - Defaults to a general-purpose legal assistant prompt if not provided. - """ - - model: str - """LLM model identifier. Defaults to anthropic/claude-sonnet-4.6""" - - object_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="objectIds")] - """Scope this run to specific vault object IDs. - - The agent will only access these objects. - """ - - sandbox: Optional[Sandbox] - """Custom sandbox resources (cpu, memoryMiB)""" - - vault_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultIds")] - """Restrict agent to specific vault IDs""" - - -class Sandbox(TypedDict, total=False): - """Custom sandbox resources (cpu, memoryMiB)""" - - cpu: int - """Number of CPUs""" - - memory_mi_b: Annotated[int, PropertyInfo(alias="memoryMiB")] - """Memory in MiB""" diff --git a/src/casedev/types/agent/v1/execute_create_response.py b/src/casedev/types/agent/v1/execute_create_response.py deleted file mode 100644 index 018d200a..00000000 --- a/src/casedev/types/agent/v1/execute_create_response.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ExecuteCreateResponse"] - - -class ExecuteCreateResponse(BaseModel): - agent_id: Optional[str] = FieldInfo(alias="agentId", default=None) - """Ephemeral agent ID (auto-created). - - This agent is soft-deleted when the run completes and should not be stored for - reuse. - """ - - message: Optional[str] = None - - run_id: Optional[str] = FieldInfo(alias="runId", default=None) - """Run ID — poll /agent/v1/run/:id/status""" - - status: Optional[Literal["running"]] = None diff --git a/src/casedev/types/agent/v1/run_cancel_response.py b/src/casedev/types/agent/v1/run_cancel_response.py deleted file mode 100644 index bffdcd26..00000000 --- a/src/casedev/types/agent/v1/run_cancel_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 typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["RunCancelResponse"] - - -class RunCancelResponse(BaseModel): - id: Optional[str] = None - - message: Optional[str] = None - """Present if run was already finished""" - - status: Optional[Literal["cancelled", "completed", "failed"]] = None diff --git a/src/casedev/types/agent/v1/run_create_params.py b/src/casedev/types/agent/v1/run_create_params.py deleted file mode 100644 index d6a462f1..00000000 --- a/src/casedev/types/agent/v1/run_create_params.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo - -__all__ = ["RunCreateParams"] - - -class RunCreateParams(TypedDict, total=False): - agent_id: Required[Annotated[str, PropertyInfo(alias="agentId")]] - """ID of the agent to run""" - - prompt: Required[str] - """Task prompt for the agent""" - - callback_url: Annotated[Optional[str], PropertyInfo(alias="callbackUrl")] - """HTTPS callback URL to receive a notification when the run completes. - - Registered atomically with the run — eliminates the race condition of calling - /watch after /exec. Additional watchers can still be added via POST - /run/:id/watch. - """ - - guidance: Optional[str] - """Additional guidance for this run""" - - model: Optional[str] - """Override the agent default model for this run""" - - object_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="objectIds")] - """Scope this run to specific vault object IDs. - - The agent will only be able to access these objects during execution. - """ diff --git a/src/casedev/types/agent/v1/run_create_response.py b/src/casedev/types/agent/v1/run_create_response.py deleted file mode 100644 index 94c9e9c9..00000000 --- a/src/casedev/types/agent/v1/run_create_response.py +++ /dev/null @@ -1,23 +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 Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["RunCreateResponse"] - - -class RunCreateResponse(BaseModel): - id: Optional[str] = None - - agent_id: Optional[str] = FieldInfo(alias="agentId", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - object_ids: Optional[List[str]] = FieldInfo(alias="objectIds", default=None) - - status: Optional[Literal["queued"]] = None diff --git a/src/casedev/types/agent/v1/run_events_params.py b/src/casedev/types/agent/v1/run_events_params.py deleted file mode 100644 index d84c2f53..00000000 --- a/src/casedev/types/agent/v1/run_events_params.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RunEventsParams"] - - -class RunEventsParams(TypedDict, total=False): - last_event_id: Annotated[int, PropertyInfo(alias="lastEventId")] - """Replay events after this sequence number""" diff --git a/src/casedev/types/agent/v1/run_events_response.py b/src/casedev/types/agent/v1/run_events_response.py deleted file mode 100644 index 2f6d8654..00000000 --- a/src/casedev/types/agent/v1/run_events_response.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import TypeAlias - -__all__ = ["RunEventsResponse"] - -RunEventsResponse: TypeAlias = str diff --git a/src/casedev/types/agent/v1/run_exec_response.py b/src/casedev/types/agent/v1/run_exec_response.py deleted file mode 100644 index 75d7a5f0..00000000 --- a/src/casedev/types/agent/v1/run_exec_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["RunExecResponse"] - - -class RunExecResponse(BaseModel): - id: Optional[str] = None - - message: Optional[str] = None - - status: Optional[Literal["running"]] = None - - workflow_id: Optional[str] = FieldInfo(alias="workflowId", default=None) - """Durable workflow run ID""" diff --git a/src/casedev/types/agent/v1/run_get_details_response.py b/src/casedev/types/agent/v1/run_get_details_response.py deleted file mode 100644 index eb56113f..00000000 --- a/src/casedev/types/agent/v1/run_get_details_response.py +++ /dev/null @@ -1,176 +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 Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = [ - "RunGetDetailsResponse", - "Result", - "ResultFinalResponse", - "ResultLogs", - "Step", - "Usage", - "UsageEntry", - "UsageSummary", -] - - -class ResultFinalResponse(BaseModel): - """Compact agent-facing result summary and execution issues""" - - created_object_ids: Optional[List[str]] = FieldInfo(alias="createdObjectIds", default=None) - - issues: Optional[List[str]] = None - - summary: Optional[str] = None - - -class ResultLogs(BaseModel): - """Sandbox execution logs (runtime server + runner script)""" - - opencode: Optional[str] = None - """Legacy runtime server stdout/stderr""" - - runner: Optional[str] = None - """Runner script stdout/stderr""" - - runtime: Optional[str] = None - """Runtime server stdout/stderr""" - - -class Result(BaseModel): - """Final output from the agent""" - - final_response: Optional[ResultFinalResponse] = FieldInfo(alias="finalResponse", default=None) - """Compact agent-facing result summary and execution issues""" - - logs: Optional[ResultLogs] = None - """Sandbox execution logs (runtime server + runner script)""" - - output: Optional[str] = None - - output_object_ids: Optional[List[str]] = FieldInfo(alias="outputObjectIds", default=None) - - -class Step(BaseModel): - id: Optional[str] = None - - content: Optional[str] = None - - duration_ms: Optional[int] = FieldInfo(alias="durationMs", default=None) - - timestamp: Optional[datetime] = None - - tool_input: Optional[object] = FieldInfo(alias="toolInput", default=None) - - tool_name: Optional[str] = FieldInfo(alias="toolName", default=None) - - tool_output: Optional[object] = FieldInfo(alias="toolOutput", default=None) - - type: Optional[Literal["output", "thinking", "tool_call", "tool_result"]] = None - - -class UsageEntry(BaseModel): - id: Optional[str] = None - - completion_tokens: Optional[int] = FieldInfo(alias="completionTokens", default=None) - - cost_micros: Optional[int] = FieldInfo(alias="costMicros", default=None) - - endpoint: Optional[str] = None - - kind: Optional[Literal["llm", "api"]] = None - - metadata: Optional[object] = None - - method: Optional[str] = None - - model: Optional[str] = None - - prompt_tokens: Optional[int] = FieldInfo(alias="promptTokens", default=None) - - service: Optional[str] = None - - status_code: Optional[int] = FieldInfo(alias="statusCode", default=None) - - timestamp: Optional[datetime] = None - - total_tokens: Optional[int] = FieldInfo(alias="totalTokens", default=None) - - -class UsageSummary(BaseModel): - cost_micros: Optional[int] = FieldInfo(alias="costMicros", default=None) - - total_input_tokens: Optional[int] = FieldInfo(alias="totalInputTokens", default=None) - - total_output_tokens: Optional[int] = FieldInfo(alias="totalOutputTokens", default=None) - - total_tokens: Optional[int] = FieldInfo(alias="totalTokens", default=None) - - -class Usage(BaseModel): - """Token usage statistics""" - - duration_ms: Optional[int] = FieldInfo(alias="durationMs", default=None) - - entries: Optional[List[UsageEntry]] = None - - input_tokens: Optional[int] = FieldInfo(alias="inputTokens", default=None) - - model: Optional[str] = None - - output_tokens: Optional[int] = FieldInfo(alias="outputTokens", default=None) - - summary: Optional[UsageSummary] = None - - tool_calls: Optional[int] = FieldInfo(alias="toolCalls", default=None) - - -class RunGetDetailsResponse(BaseModel): - id: Optional[str] = None - - agent_id: Optional[str] = FieldInfo(alias="agentId", default=None) - - completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - guidance: Optional[str] = None - - modal_sandbox_id: Optional[str] = FieldInfo(alias="modalSandboxId", default=None) - """Deprecated legacy Modal sandbox ID. Prefer `provider` and `runtimeId`.""" - - model: Optional[str] = None - - prompt: Optional[str] = None - - provider: Optional[Literal["daytona", "vercel"]] = None - """Runtime provider for this run""" - - result: Optional[Result] = None - """Final output from the agent""" - - runtime_id: Optional[str] = FieldInfo(alias="runtimeId", default=None) - """Provider-specific runtime identifier""" - - runtime_state: Optional[Literal["running", "stopped", "archived", "ended", "error"]] = FieldInfo( - alias="runtimeState", default=None - ) - """Current runtime state, when available""" - - started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None) - - status: Optional[Literal["queued", "running", "completed", "failed", "cancelled"]] = None - - steps: Optional[List[Step]] = None - - usage: Optional[Usage] = None - """Token usage statistics""" - - workflow_id: Optional[str] = FieldInfo(alias="workflowId", default=None) - """Durable workflow run ID""" diff --git a/src/casedev/types/agent/v1/run_get_status_response.py b/src/casedev/types/agent/v1/run_get_status_response.py deleted file mode 100644 index 4bb9a677..00000000 --- a/src/casedev/types/agent/v1/run_get_status_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["RunGetStatusResponse"] - - -class RunGetStatusResponse(BaseModel): - id: Optional[str] = None - - completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) - - duration_ms: Optional[int] = FieldInfo(alias="durationMs", default=None) - """Elapsed time in milliseconds""" - - started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None) - - status: Optional[Literal["queued", "running", "completed", "failed", "cancelled"]] = None diff --git a/src/casedev/types/agent/v1/run_list_params.py b/src/casedev/types/agent/v1/run_list_params.py deleted file mode 100644 index b38a400b..00000000 --- a/src/casedev/types/agent/v1/run_list_params.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RunListParams"] - - -class RunListParams(TypedDict, total=False): - agent_id: Annotated[str, PropertyInfo(alias="agentId")] - """Filter by agent ID""" - - cursor: str - """Pagination cursor (run ID from previous page). - - Returns runs created before this run. - """ - - limit: int - """Maximum number of runs to return (default 50, max 250)""" - - status: Literal["queued", "running", "completed", "failed", "cancelled"] - """Filter by run status""" diff --git a/src/casedev/types/agent/v1/run_list_response.py b/src/casedev/types/agent/v1/run_list_response.py deleted file mode 100644 index 94ce4842..00000000 --- a/src/casedev/types/agent/v1/run_list_response.py +++ /dev/null @@ -1,39 +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 Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["RunListResponse", "Run"] - - -class Run(BaseModel): - id: Optional[str] = None - - agent_id: Optional[str] = FieldInfo(alias="agentId", default=None) - - completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - model: Optional[str] = None - - prompt: Optional[str] = None - """Truncated to first 200 characters""" - - started_at: Optional[datetime] = FieldInfo(alias="startedAt", default=None) - - status: Optional[Literal["queued", "running", "completed", "failed", "cancelled"]] = None - - -class RunListResponse(BaseModel): - has_more: Optional[bool] = FieldInfo(alias="hasMore", default=None) - - next_cursor: Optional[str] = FieldInfo(alias="nextCursor", default=None) - """Pass as cursor to fetch the next page""" - - runs: Optional[List[Run]] = None diff --git a/src/casedev/types/agent/v1/run_watch_params.py b/src/casedev/types/agent/v1/run_watch_params.py deleted file mode 100644 index 8b80a795..00000000 --- a/src/casedev/types/agent/v1/run_watch_params.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RunWatchParams"] - - -class RunWatchParams(TypedDict, total=False): - callback_url: Required[Annotated[str, PropertyInfo(alias="callbackUrl")]] - """HTTPS URL to receive completion callback""" diff --git a/src/casedev/types/agent/v1/run_watch_response.py b/src/casedev/types/agent/v1/run_watch_response.py deleted file mode 100644 index bf336e5d..00000000 --- a/src/casedev/types/agent/v1/run_watch_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["RunWatchResponse"] - - -class RunWatchResponse(BaseModel): - callback_url: Optional[str] = FieldInfo(alias="callbackUrl", default=None) - - ok: Optional[bool] = None diff --git a/src/casedev/types/connectors/__init__.py b/src/casedev/types/connectors/__init__.py new file mode 100644 index 00000000..bac598e1 --- /dev/null +++ b/src/casedev/types/connectors/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .v1_transfer_params import V1TransferParams as V1TransferParams +from .v1_sync_link_params import V1SyncLinkParams as V1SyncLinkParams +from .v1_transfer_response import V1TransferResponse as V1TransferResponse +from .v1_sync_link_response import V1SyncLinkResponse as V1SyncLinkResponse diff --git a/src/casedev/types/connectors/v1/__init__.py b/src/casedev/types/connectors/v1/__init__.py new file mode 100644 index 00000000..70a6e820 --- /dev/null +++ b/src/casedev/types/connectors/v1/__init__.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .link_list_params import LinkListParams as LinkListParams +from .link_delete_params import LinkDeleteParams as LinkDeleteParams +from .link_update_params import LinkUpdateParams as LinkUpdateParams +from .connection_list_params import ConnectionListParams as ConnectionListParams +from .connection_browse_params import ConnectionBrowseParams as ConnectionBrowseParams +from .connection_create_params import ConnectionCreateParams as ConnectionCreateParams +from .connection_delete_params import ConnectionDeleteParams as ConnectionDeleteParams +from .connection_list_response import ConnectionListResponse as ConnectionListResponse +from .installation_list_params import InstallationListParams as InstallationListParams +from .link_list_objects_params import LinkListObjectsParams as LinkListObjectsParams +from .connection_browse_response import ConnectionBrowseResponse as ConnectionBrowseResponse +from .connection_create_response import ConnectionCreateResponse as ConnectionCreateResponse +from .installation_ensure_params import InstallationEnsureParams as InstallationEnsureParams diff --git a/src/casedev/types/connectors/v1/connection_browse_params.py b/src/casedev/types/connectors/v1/connection_browse_params.py new file mode 100644 index 00000000..a59e7886 --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_browse_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ConnectionBrowseParams"] + + +class ConnectionBrowseParams(TypedDict, total=False): + container: str + """Container id to list, or the container containing parent""" + + cursor: str + + page_size: int + + parent: str + """Folder id to list""" + + query: str + """Optional provider-supported search text""" + + site: str + """Site id to list""" diff --git a/src/casedev/types/connectors/v1/connection_browse_response.py b/src/casedev/types/connectors/v1/connection_browse_response.py new file mode 100644 index 00000000..e6f59a9b --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_browse_response.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ConnectionBrowseResponse", "Item"] + + +class Item(BaseModel): + id: Optional[str] = None + + browse_ref: Optional[object] = None + + container_id: Optional[str] = None + + kind: Optional[Literal["my_drive", "shared_drive", "matter", "site", "document_library", "folder", "file"]] = None + + mime_type: Optional[str] = None + + modified_at: Optional[str] = None + + name: Optional[str] = None + + parent_ids: Optional[List[str]] = None + + path: Optional[str] = None + + size_bytes: Optional[int] = None + + +class ConnectionBrowseResponse(BaseModel): + cursor: Optional[str] = None + + items: Optional[List[Item]] = None diff --git a/src/casedev/types/connectors/v1/connection_create_params.py b/src/casedev/types/connectors/v1/connection_create_params.py new file mode 100644 index 00000000..3a497030 --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_create_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 Literal, Required, TypedDict + +__all__ = ["ConnectionCreateParams"] + + +class ConnectionCreateParams(TypedDict, total=False): + provider: Required[Literal["clio", "gdrive", "microsoft"]] + + return_url: Required[str] + """HTTPS URL the user is sent back to after consent.""" + + scope_tier: Literal["clio.us", "drive", "microsoft.read"] + """Provider-specific OAuth permission tier. Omit to use the provider's default.""" diff --git a/src/casedev/types/connectors/v1/connection_create_response.py b/src/casedev/types/connectors/v1/connection_create_response.py new file mode 100644 index 00000000..35cb8354 --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_create_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["ConnectionCreateResponse"] + + +class ConnectionCreateResponse(BaseModel): + connect_url: Optional[str] = None + + connection_id: Optional[str] = None + + expires_at: Optional[str] = None diff --git a/src/casedev/types/connectors/v1/connection_delete_params.py b/src/casedev/types/connectors/v1/connection_delete_params.py new file mode 100644 index 00000000..3d9393fc --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_delete_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 TypedDict + +__all__ = ["ConnectionDeleteParams"] + + +class ConnectionDeleteParams(TypedDict, total=False): + purge: bool diff --git a/src/casedev/types/connectors/v1/connection_list_params.py b/src/casedev/types/connectors/v1/connection_list_params.py new file mode 100644 index 00000000..499dad23 --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_list_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 Literal, TypedDict + +__all__ = ["ConnectionListParams"] + + +class ConnectionListParams(TypedDict, total=False): + provider: str + + status: Literal["pending", "healthy", "reauth_required", "revoked", "throttled"] diff --git a/src/casedev/types/connectors/v1/connection_list_response.py b/src/casedev/types/connectors/v1/connection_list_response.py new file mode 100644 index 00000000..b757da49 --- /dev/null +++ b/src/casedev/types/connectors/v1/connection_list_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["ConnectionListResponse", "Capabilities"] + + +class Capabilities(BaseModel): + google_drive_folder_mirroring: Optional[bool] = None + + +class ConnectionListResponse(BaseModel): + capabilities: Optional[Capabilities] = None + + connections: Optional[List[object]] = None + + cursor: Optional[str] = None diff --git a/src/casedev/types/connectors/v1/installation_ensure_params.py b/src/casedev/types/connectors/v1/installation_ensure_params.py new file mode 100644 index 00000000..67838149 --- /dev/null +++ b/src/casedev/types/connectors/v1/installation_ensure_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_extensions import Required, TypedDict + +__all__ = ["InstallationEnsureParams"] + + +class InstallationEnsureParams(TypedDict, total=False): + application: Required[str] + """Consuming application key (e.g. "p3").""" + + external_tenant_id: Required[str] + """The application's own tenant identifier (e.g. a P3 organization id).""" diff --git a/src/casedev/types/connectors/v1/installation_list_params.py b/src/casedev/types/connectors/v1/installation_list_params.py new file mode 100644 index 00000000..127b7ef9 --- /dev/null +++ b/src/casedev/types/connectors/v1/installation_list_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 TypedDict + +__all__ = ["InstallationListParams"] + + +class InstallationListParams(TypedDict, total=False): + application: str + + external_tenant_id: str diff --git a/src/casedev/types/mail/__init__.py b/src/casedev/types/connectors/v1/installations/__init__.py similarity index 63% rename from src/casedev/types/mail/__init__.py rename to src/casedev/types/connectors/v1/installations/__init__.py index f8ee8b14..c5bb68eb 100644 --- a/src/casedev/types/mail/__init__.py +++ b/src/casedev/types/connectors/v1/installations/__init__.py @@ -1,3 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations + +from .vault_grant_params import VaultGrantParams as VaultGrantParams diff --git a/src/casedev/types/connectors/v1/installations/vault_grant_params.py b/src/casedev/types/connectors/v1/installations/vault_grant_params.py new file mode 100644 index 00000000..8080f447 --- /dev/null +++ b/src/casedev/types/connectors/v1/installations/vault_grant_params.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 Literal, Required, TypedDict + +__all__ = ["VaultGrantParams"] + + +class VaultGrantParams(TypedDict, total=False): + id: Required[str] + + can_manage: bool + + can_read: bool + + can_write: bool + + relationship: Literal["owned", "shared"] + + source: Literal["provisioning", "lazy_reconcile", "explicit_share"] diff --git a/src/casedev/types/connectors/v1/link_delete_params.py b/src/casedev/types/connectors/v1/link_delete_params.py new file mode 100644 index 00000000..d8261f30 --- /dev/null +++ b/src/casedev/types/connectors/v1/link_delete_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 Literal, TypedDict + +__all__ = ["LinkDeleteParams"] + + +class LinkDeleteParams(TypedDict, total=False): + vault_docs: Literal["keep", "delete"] diff --git a/src/casedev/types/connectors/v1/link_list_objects_params.py b/src/casedev/types/connectors/v1/link_list_objects_params.py new file mode 100644 index 00000000..fac7dcde --- /dev/null +++ b/src/casedev/types/connectors/v1/link_list_objects_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 Literal, TypedDict + +__all__ = ["LinkListObjectsParams"] + + +class LinkListObjectsParams(TypedDict, total=False): + cursor: str + + state: Literal["pending", "transferring", "ingesting", "synced", "skipped", "failed", "tombstoned"] diff --git a/src/casedev/types/connectors/v1/link_list_params.py b/src/casedev/types/connectors/v1/link_list_params.py new file mode 100644 index 00000000..2e82a4ff --- /dev/null +++ b/src/casedev/types/connectors/v1/link_list_params.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 Literal, TypedDict + +__all__ = ["LinkListParams"] + + +class LinkListParams(TypedDict, total=False): + connection_id: str + + direction: Literal["import", "export"] + + mode: Literal["once", "synced"] + + pair_id: str + + state: Literal["ready", "running", "active", "paused", "orphaned", "error"] + + vault_id: str diff --git a/src/casedev/types/connectors/v1/link_update_params.py b/src/casedev/types/connectors/v1/link_update_params.py new file mode 100644 index 00000000..4221a094 --- /dev/null +++ b/src/casedev/types/connectors/v1/link_update_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_extensions import Literal, TypedDict + +__all__ = ["LinkUpdateParams"] + + +class LinkUpdateParams(TypedDict, total=False): + mode: Literal["once", "synced"] + + policy: object + + state: Literal["paused", "ready"] diff --git a/src/casedev/types/connectors/v1_sync_link_params.py b/src/casedev/types/connectors/v1_sync_link_params.py new file mode 100644 index 00000000..2e2bf0fd --- /dev/null +++ b/src/casedev/types/connectors/v1_sync_link_params.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 Optional +from typing_extensions import Literal, Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["V1SyncLinkParams", "Remote", "Policy", "PolicyFilters"] + + +class V1SyncLinkParams(TypedDict, total=False): + connection_id: Required[str] + + direction: Required[Literal["import", "export"]] + + remote: Required[Remote] + + vault_id: Required[str] + + matter_id: Optional[str] + + policy: Policy + + +class Remote(TypedDict, total=False): + folder_id: Required[str] + + container_id: str + + path: str + + site_id: str + + +class PolicyFilters(TypedDict, total=False): + exclude_mime: SequenceNotStr[str] + + max_size_bytes: int + + +class Policy(TypedDict, total=False): + collisions: Literal["version", "overwrite", "skip"] + + deletes: Literal["mirror", "preserve"] + + filters: PolicyFilters diff --git a/src/casedev/types/connectors/v1_sync_link_response.py b/src/casedev/types/connectors/v1_sync_link_response.py new file mode 100644 index 00000000..fcf33cfb --- /dev/null +++ b/src/casedev/types/connectors/v1_sync_link_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["V1SyncLinkResponse"] + + +class V1SyncLinkResponse(BaseModel): + links: Optional[List[object]] = None diff --git a/src/casedev/types/connectors/v1_transfer_params.py b/src/casedev/types/connectors/v1_transfer_params.py new file mode 100644 index 00000000..638e7f88 --- /dev/null +++ b/src/casedev/types/connectors/v1_transfer_params.py @@ -0,0 +1,50 @@ +# 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 Literal, Required, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["V1TransferParams", "Remote", "Policy", "PolicyFilters"] + + +class V1TransferParams(TypedDict, total=False): + connection_id: Required[str] + + direction: Required[Literal["import", "export"]] + + remote: Required[Remote] + + vault_id: Required[str] + + matter_id: Optional[str] + + policy: Policy + + run_mode: Literal["auto", "full_reconcile"] + + +class Remote(TypedDict, total=False): + folder_id: Required[str] + + container_id: str + + path: str + + site_id: str + + +class PolicyFilters(TypedDict, total=False): + exclude_mime: SequenceNotStr[str] + + max_size_bytes: int + + +class Policy(TypedDict, total=False): + collisions: Literal["version", "overwrite", "skip"] + + deletes: Literal["mirror", "preserve"] + + filters: PolicyFilters diff --git a/src/casedev/types/connectors/v1_transfer_response.py b/src/casedev/types/connectors/v1_transfer_response.py new file mode 100644 index 00000000..c8fd8844 --- /dev/null +++ b/src/casedev/types/connectors/v1_transfer_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["V1TransferResponse"] + + +class V1TransferResponse(BaseModel): + links: Optional[List[object]] = None diff --git a/src/casedev/types/database/__init__.py b/src/casedev/types/database/__init__.py deleted file mode 100644 index 60ca5082..00000000 --- a/src/casedev/types/database/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1_get_usage_response import V1GetUsageResponse as V1GetUsageResponse diff --git a/src/casedev/types/database/v1/__init__.py b/src/casedev/types/database/v1/__init__.py deleted file mode 100644 index 7281d0bc..00000000 --- a/src/casedev/types/database/v1/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .project_create_params import ProjectCreateParams as ProjectCreateParams -from .project_list_response import ProjectListResponse as ProjectListResponse -from .project_create_response import ProjectCreateResponse as ProjectCreateResponse -from .project_delete_response import ProjectDeleteResponse as ProjectDeleteResponse -from .project_retrieve_response import ProjectRetrieveResponse as ProjectRetrieveResponse -from .project_create_branch_params import ProjectCreateBranchParams as ProjectCreateBranchParams -from .project_get_connection_params import ProjectGetConnectionParams as ProjectGetConnectionParams -from .project_create_branch_response import ProjectCreateBranchResponse as ProjectCreateBranchResponse -from .project_list_branches_response import ProjectListBranchesResponse as ProjectListBranchesResponse -from .project_get_connection_response import ProjectGetConnectionResponse as ProjectGetConnectionResponse diff --git a/src/casedev/types/database/v1/project_create_branch_params.py b/src/casedev/types/database/v1/project_create_branch_params.py deleted file mode 100644 index 859540a7..00000000 --- a/src/casedev/types/database/v1/project_create_branch_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["ProjectCreateBranchParams"] - - -class ProjectCreateBranchParams(TypedDict, total=False): - name: Required[str] - """Branch name (letters, numbers, hyphens, underscores only)""" - - parent_branch_id: Annotated[str, PropertyInfo(alias="parentBranchId")] - """Parent branch ID to clone from (defaults to main branch)""" diff --git a/src/casedev/types/database/v1/project_create_branch_response.py b/src/casedev/types/database/v1/project_create_branch_response.py deleted file mode 100644 index d05ea15c..00000000 --- a/src/casedev/types/database/v1/project_create_branch_response.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectCreateBranchResponse"] - - -class ProjectCreateBranchResponse(BaseModel): - id: str - """Branch ID""" - - created_at: datetime = FieldInfo(alias="createdAt") - """Branch creation timestamp""" - - is_default: bool = FieldInfo(alias="isDefault") - """Whether this is the default branch (always false for new branches)""" - - name: str - """Branch name""" - - parent_branch_id: Optional[str] = FieldInfo(alias="parentBranchId", default=None) - """Parent branch ID""" - - status: str - """Branch status""" diff --git a/src/casedev/types/database/v1/project_create_params.py b/src/casedev/types/database/v1/project_create_params.py deleted file mode 100644 index b713f720..00000000 --- a/src/casedev/types/database/v1/project_create_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ProjectCreateParams"] - - -class ProjectCreateParams(TypedDict, total=False): - name: Required[str] - """Project name (letters, numbers, hyphens, underscores only)""" - - description: str - """Optional project description""" - - region: Literal[ - "aws-us-east-1", - "aws-us-east-2", - "aws-us-west-2", - "aws-eu-central-1", - "aws-eu-west-1", - "aws-eu-west-2", - "aws-ap-southeast-1", - "aws-ap-southeast-2", - ] - """AWS region for database deployment""" diff --git a/src/casedev/types/database/v1/project_create_response.py b/src/casedev/types/database/v1/project_create_response.py deleted file mode 100644 index e2a04e93..00000000 --- a/src/casedev/types/database/v1/project_create_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# 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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectCreateResponse", "DefaultBranch"] - - -class DefaultBranch(BaseModel): - """Default 'main' branch details""" - - id: Optional[str] = None - """Branch ID""" - - name: Optional[str] = None - """Branch name""" - - -class ProjectCreateResponse(BaseModel): - id: str - """Project ID""" - - created_at: datetime = FieldInfo(alias="createdAt") - """Project creation timestamp""" - - default_branch: DefaultBranch = FieldInfo(alias="defaultBranch") - """Default 'main' branch details""" - - name: str - """Project name""" - - pg_version: int = FieldInfo(alias="pgVersion") - """PostgreSQL major version""" - - region: str - """AWS region""" - - status: Literal["active", "suspended", "deleted"] - """Project status""" - - description: Optional[str] = None - """Project description""" diff --git a/src/casedev/types/database/v1/project_delete_response.py b/src/casedev/types/database/v1/project_delete_response.py deleted file mode 100644 index 2b1640fa..00000000 --- a/src/casedev/types/database/v1/project_delete_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["ProjectDeleteResponse"] - - -class ProjectDeleteResponse(BaseModel): - message: str - """Confirmation message""" - - success: bool - """Deletion success indicator""" diff --git a/src/casedev/types/database/v1/project_get_connection_params.py b/src/casedev/types/database/v1/project_get_connection_params.py deleted file mode 100644 index a4c7c895..00000000 --- a/src/casedev/types/database/v1/project_get_connection_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["ProjectGetConnectionParams"] - - -class ProjectGetConnectionParams(TypedDict, total=False): - branch: str - """Branch name (defaults to 'main')""" - - pooled: bool - """Use pooled connection (PgBouncer)""" diff --git a/src/casedev/types/database/v1/project_get_connection_response.py b/src/casedev/types/database/v1/project_get_connection_response.py deleted file mode 100644 index 1d0cbf20..00000000 --- a/src/casedev/types/database/v1/project_get_connection_response.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectGetConnectionResponse"] - - -class ProjectGetConnectionResponse(BaseModel): - branch: str - """Branch name for this connection""" - - connection_uri: str = FieldInfo(alias="connectionUri") - """PostgreSQL connection string (includes credentials)""" - - pooled: bool - """Whether this is a pooled connection""" diff --git a/src/casedev/types/database/v1/project_list_branches_response.py b/src/casedev/types/database/v1/project_list_branches_response.py deleted file mode 100644 index 66c12778..00000000 --- a/src/casedev/types/database/v1/project_list_branches_response.py +++ /dev/null @@ -1,37 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectListBranchesResponse", "Branch"] - - -class Branch(BaseModel): - id: Optional[str] = None - """Branch ID""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Branch creation timestamp""" - - is_default: Optional[bool] = FieldInfo(alias="isDefault", default=None) - """Whether this is the default branch""" - - name: Optional[str] = None - """Branch name""" - - parent_branch_id: Optional[str] = FieldInfo(alias="parentBranchId", default=None) - """Parent branch ID (null for default branch)""" - - status: Optional[str] = None - """Branch status""" - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - """Branch last update timestamp""" - - -class ProjectListBranchesResponse(BaseModel): - branches: List[Branch] diff --git a/src/casedev/types/database/v1/project_list_response.py b/src/casedev/types/database/v1/project_list_response.py deleted file mode 100644 index 18af984c..00000000 --- a/src/casedev/types/database/v1/project_list_response.py +++ /dev/null @@ -1,64 +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 Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectListResponse", "Project", "ProjectLinkedDeployment"] - - -class ProjectLinkedDeployment(BaseModel): - id: Optional[str] = None - """Deployment ID""" - - name: Optional[str] = None - """Deployment name""" - - type: Optional[Literal["compute"]] = None - """Type of deployment""" - - url: Optional[str] = None - """Deployment URL""" - - -class Project(BaseModel): - id: Optional[str] = None - """Project ID""" - - compute_time_seconds: Optional[float] = FieldInfo(alias="computeTimeSeconds", default=None) - """Total compute time consumed in seconds""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Project creation timestamp""" - - description: Optional[str] = None - """Project description""" - - linked_deployments: Optional[List[ProjectLinkedDeployment]] = FieldInfo(alias="linkedDeployments", default=None) - """Linked application deployments using this database""" - - name: Optional[str] = None - """Project name""" - - pg_version: Optional[int] = FieldInfo(alias="pgVersion", default=None) - """PostgreSQL major version""" - - region: Optional[str] = None - """AWS region where database is deployed""" - - status: Optional[Literal["active", "suspended", "deleted"]] = None - """Current project status""" - - storage_size_bytes: Optional[float] = FieldInfo(alias="storageSizeBytes", default=None) - """Current storage usage in bytes""" - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - """Project last update timestamp""" - - -class ProjectListResponse(BaseModel): - projects: List[Project] diff --git a/src/casedev/types/database/v1/project_retrieve_response.py b/src/casedev/types/database/v1/project_retrieve_response.py deleted file mode 100644 index 789cd9c0..00000000 --- a/src/casedev/types/database/v1/project_retrieve_response.py +++ /dev/null @@ -1,100 +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 Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["ProjectRetrieveResponse", "Branch", "Database", "LinkedDeployment"] - - -class Branch(BaseModel): - id: Optional[str] = None - """Branch ID""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Branch creation timestamp""" - - is_default: Optional[bool] = FieldInfo(alias="isDefault", default=None) - """Whether this is the default branch""" - - name: Optional[str] = None - """Branch name""" - - status: Optional[str] = None - """Branch status""" - - -class Database(BaseModel): - id: Optional[str] = None - """Database ID""" - - name: Optional[str] = None - """Database name""" - - owner_name: Optional[str] = FieldInfo(alias="ownerName", default=None) - """Database owner role name""" - - -class LinkedDeployment(BaseModel): - id: Optional[str] = None - """Deployment ID""" - - env_var_name: Optional[str] = FieldInfo(alias="envVarName", default=None) - """Environment variable name for connection string""" - - name: Optional[str] = None - """Deployment name""" - - type: Optional[Literal["compute"]] = None - """Deployment type""" - - url: Optional[str] = None - """Deployment URL""" - - -class ProjectRetrieveResponse(BaseModel): - id: str - """Project ID""" - - branches: List[Branch] - """All branches in this project""" - - compute_time_seconds: float = FieldInfo(alias="computeTimeSeconds") - """Total compute time consumed in seconds""" - - connection_host: str = FieldInfo(alias="connectionHost") - """Database connection hostname (masked for security)""" - - created_at: datetime = FieldInfo(alias="createdAt") - """Project creation timestamp""" - - databases: List[Database] - """Databases in the default branch""" - - linked_deployments: List[LinkedDeployment] = FieldInfo(alias="linkedDeployments") - """Linked deployments using this database""" - - name: str - """Project name""" - - pg_version: int = FieldInfo(alias="pgVersion") - """PostgreSQL major version""" - - region: str - """AWS region""" - - status: Literal["active", "suspended", "deleted"] - """Project status""" - - storage_size_bytes: float = FieldInfo(alias="storageSizeBytes") - """Current storage usage in bytes""" - - updated_at: datetime = FieldInfo(alias="updatedAt") - """Project last update timestamp""" - - description: Optional[str] = None - """Project description""" diff --git a/src/casedev/types/database/v1_get_usage_response.py b/src/casedev/types/database/v1_get_usage_response.py deleted file mode 100644 index dc44fec6..00000000 --- a/src/casedev/types/database/v1_get_usage_response.py +++ /dev/null @@ -1,116 +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 pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["V1GetUsageResponse", "Period", "Pricing", "Project", "ProjectCosts", "Totals"] - - -class Period(BaseModel): - end: Optional[datetime] = None - """End of the billing period""" - - start: Optional[datetime] = None - """Start of the billing period""" - - -class Pricing(BaseModel): - """Current pricing rates""" - - branch_per_month: Optional[float] = FieldInfo(alias="branchPerMonth", default=None) - """Cost per branch per month in dollars""" - - compute_per_cu_hour: Optional[float] = FieldInfo(alias="computePerCuHour", default=None) - """Cost per compute unit hour in dollars""" - - free_branches: Optional[int] = FieldInfo(alias="freeBranches", default=None) - """Number of free branches included""" - - storage_per_gb_month: Optional[float] = FieldInfo(alias="storagePerGbMonth", default=None) - """Cost per GB of storage per month in dollars""" - - transfer_per_gb: Optional[float] = FieldInfo(alias="transferPerGb", default=None) - """Cost per GB of data transfer in dollars""" - - -class ProjectCosts(BaseModel): - branches: Optional[str] = None - - compute: Optional[str] = None - - storage: Optional[str] = None - - total: Optional[str] = None - - transfer: Optional[str] = None - - -class Project(BaseModel): - id: Optional[str] = None - - branch_count: Optional[int] = FieldInfo(alias="branchCount", default=None) - - compute_cu_hours: Optional[float] = FieldInfo(alias="computeCuHours", default=None) - - costs: Optional[ProjectCosts] = None - - last_updated: Optional[datetime] = FieldInfo(alias="lastUpdated", default=None) - - project_id: Optional[str] = FieldInfo(alias="projectId", default=None) - - project_name: Optional[str] = FieldInfo(alias="projectName", default=None) - - storage_gb_months: Optional[float] = FieldInfo(alias="storageGbMonths", default=None) - - transfer_gb: Optional[float] = FieldInfo(alias="transferGb", default=None) - - -class Totals(BaseModel): - """Aggregated totals across all projects""" - - branch_cost_dollars: Optional[str] = FieldInfo(alias="branchCostDollars", default=None) - """Total branch cost formatted as dollars""" - - compute_cost_dollars: Optional[str] = FieldInfo(alias="computeCostDollars", default=None) - """Total compute cost formatted as dollars""" - - compute_cu_hours: Optional[float] = FieldInfo(alias="computeCuHours", default=None) - """Total compute unit hours""" - - storage_cost_dollars: Optional[str] = FieldInfo(alias="storageCostDollars", default=None) - """Total storage cost formatted as dollars""" - - storage_gb_months: Optional[float] = FieldInfo(alias="storageGbMonths", default=None) - """Total storage in GB-months""" - - total_branches: Optional[int] = FieldInfo(alias="totalBranches", default=None) - """Total number of branches""" - - total_cost_dollars: Optional[str] = FieldInfo(alias="totalCostDollars", default=None) - """Total cost formatted as dollars""" - - transfer_cost_dollars: Optional[str] = FieldInfo(alias="transferCostDollars", default=None) - """Total transfer cost formatted as dollars""" - - transfer_gb: Optional[float] = FieldInfo(alias="transferGb", default=None) - """Total data transfer in GB""" - - -class V1GetUsageResponse(BaseModel): - period: Optional[Period] = None - - pricing: Optional[Pricing] = None - """Current pricing rates""" - - project_count: Optional[int] = FieldInfo(alias="projectCount", default=None) - """Total number of projects with usage""" - - projects: Optional[List[Project]] = None - """Usage breakdown by project""" - - totals: Optional[Totals] = None - """Aggregated totals across all projects""" diff --git a/src/casedev/types/format/__init__.py b/src/casedev/types/format/__init__.py deleted file mode 100644 index 287e51d3..00000000 --- a/src/casedev/types/format/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1_create_document_params import V1CreateDocumentParams as V1CreateDocumentParams diff --git a/src/casedev/types/format/v1/__init__.py b/src/casedev/types/format/v1/__init__.py deleted file mode 100644 index 351ac658..00000000 --- a/src/casedev/types/format/v1/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .template_list_params import TemplateListParams as TemplateListParams -from .template_create_params import TemplateCreateParams as TemplateCreateParams -from .template_list_response import TemplateListResponse as TemplateListResponse -from .template_create_response import TemplateCreateResponse as TemplateCreateResponse -from .template_retrieve_response import TemplateRetrieveResponse as TemplateRetrieveResponse diff --git a/src/casedev/types/format/v1/template_create_params.py b/src/casedev/types/format/v1/template_create_params.py deleted file mode 100644 index f8316608..00000000 --- a/src/casedev/types/format/v1/template_create_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ...._types import SequenceNotStr - -__all__ = ["TemplateCreateParams"] - - -class TemplateCreateParams(TypedDict, total=False): - content: Required[str] - """Template content with {{variable}} placeholders""" - - name: Required[str] - """Template name""" - - type: Required[Literal["caption", "signature", "letterhead", "certificate", "footer", "custom"]] - """Template type""" - - description: str - """Template description""" - - styles: object - """CSS styles for the template""" - - tags: SequenceNotStr[str] - """Template tags for organization""" - - variables: SequenceNotStr[str] - """Template variables (auto-detected if not provided)""" diff --git a/src/casedev/types/format/v1/template_create_response.py b/src/casedev/types/format/v1/template_create_response.py deleted file mode 100644 index ee7c7a6d..00000000 --- a/src/casedev/types/format/v1/template_create_response.py +++ /dev/null @@ -1,27 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["TemplateCreateResponse"] - - -class TemplateCreateResponse(BaseModel): - id: Optional[str] = None - """Template ID""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Creation timestamp""" - - name: Optional[str] = None - """Template name""" - - type: Optional[str] = None - """Template type""" - - variables: Optional[List[str]] = None - """Detected template variables""" diff --git a/src/casedev/types/format/v1/template_list_params.py b/src/casedev/types/format/v1/template_list_params.py deleted file mode 100644 index a134cd7e..00000000 --- a/src/casedev/types/format/v1/template_list_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 TypedDict - -__all__ = ["TemplateListParams"] - - -class TemplateListParams(TypedDict, total=False): - type: str - """Filter templates by type (e.g., contract, pleading, letter)""" diff --git a/src/casedev/types/format/v1/template_list_response.py b/src/casedev/types/format/v1/template_list_response.py deleted file mode 100644 index b5efddfc..00000000 --- a/src/casedev/types/format/v1/template_list_response.py +++ /dev/null @@ -1,40 +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 pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["TemplateListResponse", "Template"] - - -class Template(BaseModel): - id: Optional[str] = None - """Unique template identifier""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Template creation timestamp""" - - description: Optional[str] = None - """Template description""" - - name: Optional[str] = None - """Template name""" - - tags: Optional[List[object]] = None - """Template tags for organization""" - - type: Optional[str] = None - """Template type/category""" - - usage_count: Optional[int] = FieldInfo(alias="usageCount", default=None) - """Number of times template has been used""" - - variables: Optional[List[object]] = None - """Template variables for customization""" - - -class TemplateListResponse(BaseModel): - templates: Optional[List[Template]] = None diff --git a/src/casedev/types/format/v1/template_retrieve_response.py b/src/casedev/types/format/v1/template_retrieve_response.py deleted file mode 100644 index e51ca387..00000000 --- a/src/casedev/types/format/v1/template_retrieve_response.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["TemplateRetrieveResponse"] - - -class TemplateRetrieveResponse(BaseModel): - id: Optional[str] = None - """Unique template identifier""" - - content: Optional[object] = None - """Template formatting rules and structure""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Template creation timestamp""" - - description: Optional[str] = None - """Template description""" - - name: Optional[str] = None - """Template name""" - - organization_id: Optional[str] = FieldInfo(alias="organizationId", default=None) - """Organization ID that owns the template""" - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - """Template last modification timestamp""" diff --git a/src/casedev/types/format/v1_create_document_params.py b/src/casedev/types/format/v1_create_document_params.py deleted file mode 100644 index 462456ab..00000000 --- a/src/casedev/types/format/v1_create_document_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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 Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["V1CreateDocumentParams", "Options", "OptionsComponent"] - - -class V1CreateDocumentParams(TypedDict, total=False): - content: Required[str] - """The source content to format""" - - output_format: Required[Literal["pdf", "docx", "html_preview"]] - """Desired output format""" - - input_format: Literal["md", "json", "text"] - """Format of the input content""" - - options: Options - """ - Optional template composition and styling settings used during document - generation - """ - - -class OptionsComponent(TypedDict, total=False): - content: str - """Inline template content""" - - styles: object - """Custom styling options""" - - template_id: Annotated[str, PropertyInfo(alias="templateId")] - """ID of saved template component""" - - variables: object - """Variables for template interpolation""" - - -class Options(TypedDict, total=False): - """ - Optional template composition and styling settings used during document generation - """ - - components: Iterable[OptionsComponent] - """Template components with variables""" diff --git a/src/casedev/types/legal/__init__.py b/src/casedev/types/legal/__init__.py index 57bc1a81..e4b2d87b 100644 --- a/src/casedev/types/legal/__init__.py +++ b/src/casedev/types/legal/__init__.py @@ -4,11 +4,9 @@ from .docket_detail import DocketDetail as DocketDetail from .v1_find_params import V1FindParams as V1FindParams -from .v1_draft_params import V1DraftParams as V1DraftParams from .v1_docket_params import V1DocketParams as V1DocketParams from .v1_find_response import V1FindResponse as V1FindResponse from .v1_verify_params import V1VerifyParams as V1VerifyParams -from .v1_draft_response import V1DraftResponse as V1DraftResponse from .v1_similar_params import V1SimilarParams as V1SimilarParams from .v1_docket_response import V1DocketResponse as V1DocketResponse from .v1_research_params import V1ResearchParams as V1ResearchParams diff --git a/src/casedev/types/legal/v1_docket_params.py b/src/casedev/types/legal/v1_docket_params.py index 523a7ee0..893ca6d3 100644 --- a/src/casedev/types/legal/v1_docket_params.py +++ b/src/casedev/types/legal/v1_docket_params.py @@ -54,7 +54,10 @@ class V1DocketParams(TypedDict, total=False): """ offset: int - """Offset for search results or entry list""" + """ + Offset for search results or entry list (maximum 200 when including lookup + entries) + """ query: str """Case name or party name search query (required for search)""" diff --git a/src/casedev/types/legal/v1_draft_params.py b/src/casedev/types/legal/v1_draft_params.py deleted file mode 100644 index 83711fbb..00000000 --- a/src/casedev/types/legal/v1_draft_params.py +++ /dev/null @@ -1,62 +0,0 @@ -# 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 Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["V1DraftParams", "Length"] - - -class V1DraftParams(TypedDict, total=False): - instructions: Required[str] - """What to draft — the core task. - - E.g., "Motion to compel defendant to produce discovery responses" - """ - - vault_id: Required[str] - """Vault ID where the final document will be uploaded""" - - citations: bool - """Research and include legal citations""" - - format: Optional[str] - """Court or jurisdiction formatting hint. - - Triggers a legal-skills search. E.g., "California Superior Court", "SDNY", - "federal pleading" - """ - - length: Optional[Length] - """Target document length""" - - model: Optional[str] - """LLM model override. Defaults to anthropic/claude-sonnet-4.6""" - - object_ids: Optional[SequenceNotStr[str]] - """Vault object IDs to use as source/reference documents""" - - output_name: Optional[str] - """Filename for the output document. Auto-generated if omitted.""" - - output_type: Literal["pdf", "docx", "xlsx", "pptx", "md"] - """Output file format""" - - verified: bool - """ - Verify all citations in a loop — re-run verification and repair bad citations - until they pass - """ - - -class Length(TypedDict, total=False): - """Target document length""" - - target: float - """Target value (e.g., 2000 words or 5 pages)""" - - unit: Literal["words", "pages"] - """Whether the target length is measured in words or pages""" diff --git a/src/casedev/types/legal/v1_draft_response.py b/src/casedev/types/legal/v1_draft_response.py deleted file mode 100644 index b462f709..00000000 --- a/src/casedev/types/legal/v1_draft_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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 - -__all__ = ["V1DraftResponse"] - - -class V1DraftResponse(BaseModel): - agent_id: Optional[str] = None - """Ephemeral agent ID""" - - message: Optional[str] = None - - run_id: Optional[str] = None - """Run ID — poll /agent/v1/run/:id/status for progress""" - - status: Optional[Literal["running"]] = None diff --git a/src/casedev/types/agent/__init__.py b/src/casedev/types/linc/__init__.py similarity index 100% rename from src/casedev/types/agent/__init__.py rename to src/casedev/types/linc/__init__.py diff --git a/src/casedev/types/linc/v1/__init__.py b/src/casedev/types/linc/v1/__init__.py new file mode 100644 index 00000000..3629df9e --- /dev/null +++ b/src/casedev/types/linc/v1/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .session_cancel_params import SessionCancelParams as SessionCancelParams +from .session_create_params import SessionCreateParams as SessionCreateParams +from .session_send_rpc_params import SessionSendRpcParams as SessionSendRpcParams +from .session_ingest_events_params import SessionIngestEventsParams as SessionIngestEventsParams +from .session_retrieve_events_params import SessionRetrieveEventsParams as SessionRetrieveEventsParams +from .session_retrieve_messages_params import SessionRetrieveMessagesParams as SessionRetrieveMessagesParams diff --git a/src/casedev/types/linc/v1/session_cancel_params.py b/src/casedev/types/linc/v1/session_cancel_params.py new file mode 100644 index 00000000..aea535a3 --- /dev/null +++ b/src/casedev/types/linc/v1/session_cancel_params.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 Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["SessionCancelParams"] + + +class SessionCancelParams(TypedDict, total=False): + clear_queue: Annotated[bool, PropertyInfo(alias="clearQueue")] + """ + Also clear queued steering/follow-up messages so the abort leaves the agent + fully idle. Cleared texts are returned in the `response.data.clearedQueue` field + of the response body. Without it, messages still queued when the abort settles + are auto-continued as a new run. Runtimes older than the Linc release that + supports this flag ignore it: the abort still happens but the queue is left + untouched. + """ diff --git a/src/casedev/types/linc/v1/session_create_params.py b/src/casedev/types/linc/v1/session_create_params.py new file mode 100644 index 00000000..2d58fd18 --- /dev/null +++ b/src/casedev/types/linc/v1/session_create_params.py @@ -0,0 +1,51 @@ +# 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 Literal, Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = ["SessionCreateParams"] + + +class SessionCreateParams(TypedDict, total=False): + document_template_slugs: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="documentTemplateSlugs")] + """ + Specific document template slugs to inject into the using-document-templates + skill. + """ + + idle_timeout_ms: Annotated[Optional[int], PropertyInfo(alias="idleTimeoutMs")] + + include_document_templates: Annotated[Optional[bool], PropertyInfo(alias="includeDocumentTemplates")] + """ + When true, inject all active org document templates into the + using-document-templates skill. + """ + + instructions: Optional[str] + """Privileged C3-only hidden app instructions to append to the sandbox AGENTS.md.""" + + model: Optional[str] + + scoped_api_key: Annotated[Optional[str], PropertyInfo(alias="scopedApiKey")] + """Optional caller-provided scoped Case.dev API key for the runtime.""" + + service_tier: Annotated[Literal["default", "priority"], PropertyInfo(alias="serviceTier")] + """Processing tier for eligible OpenAI GPT models. + + Priority provides lower latency at premium cost. + """ + + skill_slugs: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="skillSlugs")] + """ + Skills API slugs to install into the runtime sandbox before the native session + starts. + """ + + title: str + + vault_ids: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="vaultIds")] diff --git a/src/casedev/types/linc/v1/session_ingest_events_params.py b/src/casedev/types/linc/v1/session_ingest_events_params.py new file mode 100644 index 00000000..d2bcc9a4 --- /dev/null +++ b/src/casedev/types/linc/v1/session_ingest_events_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 Dict, Iterable +from typing_extensions import Required, TypedDict + +__all__ = ["SessionIngestEventsParams", "Frame"] + + +class SessionIngestEventsParams(TypedDict, total=False): + frames: Required[Iterable[Frame]] + """Native Linc event frames to persist for replay.""" + + +class Frame(TypedDict, total=False): + event: Required[Dict[str, object]] + """Native Linc event payload.""" + + seq: Required[int] + """Monotonic native event sequence number.""" + + type: Required[str] + """Native Linc event type.""" diff --git a/src/casedev/types/linc/v1/session_retrieve_events_params.py b/src/casedev/types/linc/v1/session_retrieve_events_params.py new file mode 100644 index 00000000..290bb90d --- /dev/null +++ b/src/casedev/types/linc/v1/session_retrieve_events_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_extensions import Annotated, TypedDict + +from ...._types import SequenceNotStr +from ...._utils import PropertyInfo + +__all__ = ["SessionRetrieveEventsParams"] + + +class SessionRetrieveEventsParams(TypedDict, total=False): + after_seq: Annotated[int, PropertyInfo(alias="afterSeq")] + """Alias for cursor. Ignored when cursor is also provided.""" + + cursor: int + """Replay events with a sequence number greater than this cursor.""" + + exclude_event_types: Annotated[SequenceNotStr[str], PropertyInfo(alias="excludeEventTypes")] + """Comma-separated Linc event types to omit from replay.""" + + limit: int + """Maximum number of events to return.""" diff --git a/src/casedev/types/linc/v1/session_retrieve_messages_params.py b/src/casedev/types/linc/v1/session_retrieve_messages_params.py new file mode 100644 index 00000000..5135b75b --- /dev/null +++ b/src/casedev/types/linc/v1/session_retrieve_messages_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["SessionRetrieveMessagesParams"] + + +class SessionRetrieveMessagesParams(TypedDict, total=False): + after_seq: Annotated[int, PropertyInfo(alias="afterSeq")] + """Alias for cursor. Ignored when cursor is also provided.""" + + cursor: int + """Replay messages with a source event sequence number greater than this cursor.""" + + limit: int + """Maximum number of source events to scan for completed messages.""" diff --git a/src/casedev/types/linc/v1/session_send_rpc_params.py b/src/casedev/types/linc/v1/session_send_rpc_params.py new file mode 100644 index 00000000..1abe5398 --- /dev/null +++ b/src/casedev/types/linc/v1/session_send_rpc_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["SessionSendRpcParams"] + + +class SessionSendRpcParams(TypedDict, total=False): + type: Required[str] + """Native Pi/Linc RPC command type. + + Prompt commands also require a string id for idempotency. + """ + + body_id: Annotated[str, PropertyInfo(alias="id")] + """Command idempotency key. Required when type is prompt.""" diff --git a/src/casedev/types/llm/v1/chat_create_completion_params.py b/src/casedev/types/llm/v1/chat_create_completion_params.py index ea53c526..47093d9a 100644 --- a/src/casedev/types/llm/v1/chat_create_completion_params.py +++ b/src/casedev/types/llm/v1/chat_create_completion_params.py @@ -13,9 +13,10 @@ class ChatCreateCompletionParams(TypedDict, total=False): """List of messages comprising the conversation""" casemark_show_reasoning: bool - """CaseMark-only: when true, allows reasoning fields in responses. + """CaseMark-only: controls whether reasoning fields appear in responses. - Defaults to false (reasoning is suppressed). + Defaults to false (suppressed) for most CaseMark models; defaults to true for + casemark/core-potassium. """ frequency_penalty: float diff --git a/src/casedev/types/mail/v1/__init__.py b/src/casedev/types/mail/v1/__init__.py deleted file mode 100644 index edd97ad1..00000000 --- a/src/casedev/types/mail/v1/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .inbox_create_params import InboxCreateParams as InboxCreateParams -from .inbox_set_policy_params import InboxSetPolicyParams as InboxSetPolicyParams diff --git a/src/casedev/types/mail/v1/inbox_create_params.py b/src/casedev/types/mail/v1/inbox_create_params.py deleted file mode 100644 index 405bd5fa..00000000 --- a/src/casedev/types/mail/v1/inbox_create_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["InboxCreateParams"] - - -class InboxCreateParams(TypedDict, total=False): - address: str - - display_name: Annotated[str, PropertyInfo(alias="displayName")] diff --git a/src/casedev/types/mail/v1/inbox_set_policy_params.py b/src/casedev/types/mail/v1/inbox_set_policy_params.py deleted file mode 100644 index 743ad80a..00000000 --- a/src/casedev/types/mail/v1/inbox_set_policy_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo - -__all__ = ["InboxSetPolicyParams"] - - -class InboxSetPolicyParams(TypedDict, total=False): - allowed_sender_patterns: Annotated[SequenceNotStr[str], PropertyInfo(alias="allowedSenderPatterns")] - """Exact emails, @domain rules, or \\**""" - - enforce_sender_allowlist: Annotated[bool, PropertyInfo(alias="enforceSenderAllowlist")] - - read_access_rules: Annotated[SequenceNotStr[str], PropertyInfo(alias="readAccessRules")] - """ - Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - """ - - reply_access_rules: Annotated[SequenceNotStr[str], PropertyInfo(alias="replyAccessRules")] - """ - Rules like organization, operator, user:, api_key, api_key:, - clerk_session, or \\** - """ - - send_access_rules: Annotated[SequenceNotStr[str], PropertyInfo(alias="sendAccessRules")] - """Rules like organization, user:, api_key, api_key:, clerk_session, or \\**""" diff --git a/src/casedev/types/matters/v1/work_item_decide_params.py b/src/casedev/types/matters/v1/work_item_decide_params.py index 1f6e042f..dc78435b 100644 --- a/src/casedev/types/matters/v1/work_item_decide_params.py +++ b/src/casedev/types/matters/v1/work_item_decide_params.py @@ -11,9 +11,7 @@ class WorkItemDecideParams(TypedDict, total=False): id: Required[str] - decision: Required[Literal["approve", "revise", "block", "reassign"]] - - agent_type_id: Optional[str] + decision: Required[Literal["approve", "block"]] metadata: Dict[str, object] diff --git a/src/casedev/types/media/v1/transcripts/__init__.py b/src/casedev/types/media/v1/transcripts/__init__.py index f8ee8b14..ad7efe60 100644 --- a/src/casedev/types/media/v1/transcripts/__init__.py +++ b/src/casedev/types/media/v1/transcripts/__init__.py @@ -1,3 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations + +from .retrieve_create_params import RetrieveCreateParams as RetrieveCreateParams +from .retrieve_create_response import RetrieveCreateResponse as RetrieveCreateResponse diff --git a/src/casedev/types/media/v1/transcripts/retrieve_create_params.py b/src/casedev/types/media/v1/transcripts/retrieve_create_params.py new file mode 100644 index 00000000..3e31cb3b --- /dev/null +++ b/src/casedev/types/media/v1/transcripts/retrieve_create_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["RetrieveCreateParams", "Transcript"] + + +class RetrieveCreateParams(TypedDict, total=False): + object_id: Required[str] + """Object ID for either the source audio/video file or transcript artifact.""" + + vault_id: Required[str] + """Vault ID containing the source media or transcript object.""" + + transcript: Transcript + """Alternative nested transcript object reference.""" + + +class Transcript(TypedDict, total=False): + """Alternative nested transcript object reference.""" + + object_id: str + + vault_id: str diff --git a/src/casedev/types/media/v1/transcripts/retrieve_create_response.py b/src/casedev/types/media/v1/transcripts/retrieve_create_response.py new file mode 100644 index 00000000..714f7c55 --- /dev/null +++ b/src/casedev/types/media/v1/transcripts/retrieve_create_response.py @@ -0,0 +1,37 @@ +# 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 + +__all__ = ["RetrieveCreateResponse"] + + +class RetrieveCreateResponse(BaseModel): + object_id: str + """Requested object ID.""" + + status: Literal["completed"] + + text: str + """Full transcript text.""" + + vault_id: str + + audio_duration: Optional[int] = None + + confidence: Optional[int] = None + + filename: Optional[str] = None + + source_object_id: Optional[str] = None + """Source media object ID when known.""" + + transcript_object_id: Optional[str] = None + """Transcript object ID when known.""" + + transcription_job_id: Optional[str] = None + """Transcription job ID when known.""" + + word_count: Optional[int] = None diff --git a/src/casedev/types/ocr/v1_process_params.py b/src/casedev/types/ocr/v1_process_params.py index 7f6e99c4..f3f863eb 100644 --- a/src/casedev/types/ocr/v1_process_params.py +++ b/src/casedev/types/ocr/v1_process_params.py @@ -31,7 +31,11 @@ class V1ProcessParams(TypedDict, total=False): """S3 key prefix for results""" -class FeaturesTables(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class FeaturesTables( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """Extract tables as structured data""" format: Literal["csv", "json"] diff --git a/src/casedev/types/ocr/v1_retrieve_params.py b/src/casedev/types/ocr/v1_retrieve_params.py index 65ba0218..d5b674bf 100644 --- a/src/casedev/types/ocr/v1_retrieve_params.py +++ b/src/casedev/types/ocr/v1_retrieve_params.py @@ -9,4 +9,4 @@ class V1RetrieveParams(TypedDict, total=False): include_text: Literal["true", "false"] - """Include full OCR text in completed responses (default: true)""" + """Include full OCR text in completed responses (default: false)""" diff --git a/src/casedev/types/ocr/v1_retrieve_response.py b/src/casedev/types/ocr/v1_retrieve_response.py index a5a6ca8a..d7173544 100644 --- a/src/casedev/types/ocr/v1_retrieve_response.py +++ b/src/casedev/types/ocr/v1_retrieve_response.py @@ -29,4 +29,4 @@ class V1RetrieveResponse(BaseModel): """Number of pages processed""" text: Optional[str] = None - """Extracted text content (when completed)""" + """Extracted text content when completed and include_text=true""" diff --git a/src/casedev/types/search/__init__.py b/src/casedev/types/search/__init__.py index bd520293..5365d86e 100644 --- a/src/casedev/types/search/__init__.py +++ b/src/casedev/types/search/__init__.py @@ -7,10 +7,6 @@ from .v1_similar_params import V1SimilarParams as V1SimilarParams from .v1_answer_response import V1AnswerResponse as V1AnswerResponse from .v1_contents_params import V1ContentsParams as V1ContentsParams -from .v1_research_params import V1ResearchParams as V1ResearchParams from .v1_search_response import V1SearchResponse as V1SearchResponse from .v1_similar_response import V1SimilarResponse as V1SimilarResponse from .v1_contents_response import V1ContentsResponse as V1ContentsResponse -from .v1_research_response import V1ResearchResponse as V1ResearchResponse -from .v1_retrieve_research_params import V1RetrieveResearchParams as V1RetrieveResearchParams -from .v1_retrieve_research_response import V1RetrieveResearchResponse as V1RetrieveResearchResponse diff --git a/src/casedev/types/search/v1_research_params.py b/src/casedev/types/search/v1_research_params.py deleted file mode 100644 index ea5924af..00000000 --- a/src/casedev/types/search/v1_research_params.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["V1ResearchParams"] - - -class V1ResearchParams(TypedDict, total=False): - instructions: Required[str] - """Research instructions or query""" - - model: Literal["fast", "normal", "pro"] - """Research quality level - fast (quick), normal (balanced), pro (comprehensive)""" - - output_schema: Annotated[object, PropertyInfo(alias="outputSchema")] - """Optional JSON schema to structure the research output""" - - query: str - """Alias for instructions (for convenience)""" diff --git a/src/casedev/types/search/v1_research_response.py b/src/casedev/types/search/v1_research_response.py deleted file mode 100644 index db1b1259..00000000 --- a/src/casedev/types/search/v1_research_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["V1ResearchResponse"] - - -class V1ResearchResponse(BaseModel): - model: Optional[str] = None - """Model used for research""" - - research_id: Optional[str] = FieldInfo(alias="researchId", default=None) - """Unique identifier for this research""" - - results: Optional[object] = None - """Research findings and analysis""" diff --git a/src/casedev/types/search/v1_retrieve_research_params.py b/src/casedev/types/search/v1_retrieve_research_params.py deleted file mode 100644 index c62a5e1c..00000000 --- a/src/casedev/types/search/v1_retrieve_research_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["V1RetrieveResearchParams"] - - -class V1RetrieveResearchParams(TypedDict, total=False): - events: str - """Filter specific event types for streaming""" - - stream: bool - """Enable streaming for real-time updates""" diff --git a/src/casedev/types/search/v1_retrieve_research_response.py b/src/casedev/types/search/v1_retrieve_research_response.py deleted file mode 100644 index 2e05e7d6..00000000 --- a/src/casedev/types/search/v1_retrieve_research_response.py +++ /dev/null @@ -1,74 +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 Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["V1RetrieveResearchResponse", "Results", "ResultsSection", "ResultsSectionSource", "ResultsSource"] - - -class ResultsSectionSource(BaseModel): - snippet: Optional[str] = None - - title: Optional[str] = None - - url: Optional[str] = None - - -class ResultsSection(BaseModel): - content: Optional[str] = None - - sources: Optional[List[ResultsSectionSource]] = None - - title: Optional[str] = None - - -class ResultsSource(BaseModel): - snippet: Optional[str] = None - - title: Optional[str] = None - - url: Optional[str] = None - - -class Results(BaseModel): - """Research findings and analysis""" - - sections: Optional[List[ResultsSection]] = None - """Detailed research sections""" - - sources: Optional[List[ResultsSource]] = None - """All sources referenced in research""" - - summary: Optional[str] = None - """Executive summary of research findings""" - - -class V1RetrieveResearchResponse(BaseModel): - id: Optional[str] = None - """Research task ID""" - - completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) - """Task completion timestamp""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """Task creation timestamp""" - - model: Optional[Literal["fast", "normal", "pro"]] = None - """Research model used""" - - progress: Optional[float] = None - """Completion percentage (0-100)""" - - query: Optional[str] = None - """Original research query""" - - results: Optional[Results] = None - """Research findings and analysis""" - - status: Optional[Literal["pending", "running", "completed", "failed"]] = None - """Current status of the research task""" diff --git a/src/casedev/types/superdoc/__init__.py b/src/casedev/types/superdoc/__init__.py deleted file mode 100644 index 111238a8..00000000 --- a/src/casedev/types/superdoc/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .v1_convert_params import V1ConvertParams as V1ConvertParams -from .v1_annotate_params import V1AnnotateParams as V1AnnotateParams diff --git a/src/casedev/types/superdoc/v1_annotate_params.py b/src/casedev/types/superdoc/v1_annotate_params.py deleted file mode 100644 index fc0321ba..00000000 --- a/src/casedev/types/superdoc/v1_annotate_params.py +++ /dev/null @@ -1,56 +0,0 @@ -# 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, TypedDict - -__all__ = ["V1AnnotateParams", "Document", "Field", "FieldOptions"] - - -class V1AnnotateParams(TypedDict, total=False): - document: Required[Document] - """Document source - provide either URL or base64""" - - fields: Required[Iterable[Field]] - """Fields to populate in the template""" - - output_format: Literal["docx", "pdf"] - """Output format for the annotated document""" - - -class Document(TypedDict, total=False): - """Document source - provide either URL or base64""" - - base64: str - """Base64-encoded DOCX template""" - - url: str - """URL to the DOCX template""" - - -class FieldOptions(TypedDict, total=False): - """Optional configuration (e.g., image dimensions)""" - - height: float - """Image height in pixels""" - - width: float - """Image width in pixels""" - - -class Field(TypedDict, total=False): - type: Required[Literal["text", "image", "date", "number"]] - """Field data type""" - - value: Required[Union[str, float]] - """Value to populate""" - - id: str - """Target field ID (for single field)""" - - group: str - """Target field group (for multiple fields with same tag)""" - - options: FieldOptions - """Optional configuration (e.g., image dimensions)""" diff --git a/src/casedev/types/superdoc/v1_convert_params.py b/src/casedev/types/superdoc/v1_convert_params.py deleted file mode 100644 index 7e1513fb..00000000 --- a/src/casedev/types/superdoc/v1_convert_params.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["V1ConvertParams"] - - -class V1ConvertParams(TypedDict, total=False): - from_: Required[Annotated[Literal["docx", "md", "html"], PropertyInfo(alias="from")]] - """Source format of the document""" - - document_base64: str - """Base64-encoded document content""" - - document_url: str - """URL to the document to convert""" - - to: Literal["pdf", "docx"] - """Target format for conversion""" diff --git a/src/casedev/types/translate/__init__.py b/src/casedev/types/translate/__init__.py index 8df52194..28cf9f11 100644 --- a/src/casedev/types/translate/__init__.py +++ b/src/casedev/types/translate/__init__.py @@ -8,3 +8,4 @@ from .v1_translate_response import V1TranslateResponse as V1TranslateResponse from .v1_list_languages_params import V1ListLanguagesParams as V1ListLanguagesParams from .v1_list_languages_response import V1ListLanguagesResponse as V1ListLanguagesResponse +from .v1_translate_document_params import V1TranslateDocumentParams as V1TranslateDocumentParams diff --git a/src/casedev/types/translate/v1_translate_document_params.py b/src/casedev/types/translate/v1_translate_document_params.py new file mode 100644 index 00000000..64abe2d2 --- /dev/null +++ b/src/casedev/types/translate/v1_translate_document_params.py @@ -0,0 +1,20 @@ +# 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__ = ["V1TranslateDocumentParams"] + + +class V1TranslateDocumentParams(TypedDict, total=False): + file: Required[FileTypes] + """TXT, DOCX, or searchable PDF document (max 20MB)""" + + target: Required[str] + """Target BCP-47 language code""" + + source: str + """Optional source BCP-47 language code. Auto-detected when omitted.""" diff --git a/src/casedev/types/usage/v1_retrieve_params.py b/src/casedev/types/usage/v1_retrieve_params.py index bc0d74d9..26aae1a3 100644 --- a/src/casedev/types/usage/v1_retrieve_params.py +++ b/src/casedev/types/usage/v1_retrieve_params.py @@ -15,6 +15,18 @@ class V1RetrieveParams(TypedDict, total=False): granularity: Literal["summary", "daily"] """Whether to return period totals only or include daily buckets.""" + group_by: Annotated[Literal["lincSessionId"], PropertyInfo(alias="groupBy")] + """Optionally include usage groups keyed by native Linc session id. + + Only Linc-session-attributable usage is grouped. + """ + + linc_session_id: Annotated[str, PropertyInfo(alias="lincSessionId")] + """Restrict usage to a native Linc session. + + The session must belong to the authenticated organization. + """ + period_end: Annotated[Union[str, datetime], PropertyInfo(alias="periodEnd", format="iso8601")] """Period end date. Defaults to now.""" diff --git a/src/casedev/types/vault/__init__.py b/src/casedev/types/vault/__init__.py index 04f8aead..702284d9 100644 --- a/src/casedev/types/vault/__init__.py +++ b/src/casedev/types/vault/__init__.py @@ -2,33 +2,37 @@ from __future__ import annotations +from .object_list_params import ObjectListParams as ObjectListParams from .group_create_params import GroupCreateParams as GroupCreateParams from .group_update_params import GroupUpdateParams as GroupUpdateParams +from .object_merge_params import ObjectMergeParams as ObjectMergeParams from .memory_create_params import MemoryCreateParams as MemoryCreateParams from .memory_list_response import MemoryListResponse as MemoryListResponse from .memory_search_params import MemorySearchParams as MemorySearchParams from .memory_update_params import MemoryUpdateParams as MemoryUpdateParams +from .object_append_params import ObjectAppendParams as ObjectAppendParams from .object_delete_params import ObjectDeleteParams as ObjectDeleteParams from .object_list_response import ObjectListResponse as ObjectListResponse from .object_update_params import ObjectUpdateParams as ObjectUpdateParams -from .graphrag_init_response import GraphragInitResponse as GraphragInitResponse +from .multipart_init_params import MultipartInitParams as MultipartInitParams +from .object_merge_response import ObjectMergeResponse as ObjectMergeResponse from .memory_create_response import MemoryCreateResponse as MemoryCreateResponse from .memory_search_response import MemorySearchResponse as MemorySearchResponse from .multipart_abort_params import MultipartAbortParams as MultipartAbortParams +from .object_append_response import ObjectAppendResponse as ObjectAppendResponse from .object_delete_response import ObjectDeleteResponse as ObjectDeleteResponse from .object_update_response import ObjectUpdateResponse as ObjectUpdateResponse +from .multipart_init_response import MultipartInitResponse as MultipartInitResponse from .object_get_pages_params import ObjectGetPagesParams as ObjectGetPagesParams from .object_get_chunks_params import ObjectGetChunksParams as ObjectGetChunksParams from .object_get_text_response import ObjectGetTextResponse as ObjectGetTextResponse from .object_retrieve_response import ObjectRetrieveResponse as ObjectRetrieveResponse +from .multipart_complete_params import MultipartCompleteParams as MultipartCompleteParams from .object_get_pages_response import ObjectGetPagesResponse as ObjectGetPagesResponse from .object_get_chunks_response import ObjectGetChunksResponse as ObjectGetChunksResponse -from .graphrag_get_stats_response import GraphragGetStatsResponse as GraphragGetStatsResponse from .object_get_ocr_words_params import ObjectGetOcrWordsParams as ObjectGetOcrWordsParams from .object_get_ocr_words_response import ObjectGetOcrWordsResponse as ObjectGetOcrWordsResponse from .multipart_get_part_urls_params import MultipartGetPartURLsParams as MultipartGetPartURLsParams -from .graphrag_process_object_response import GraphragProcessObjectResponse as GraphragProcessObjectResponse from .multipart_get_part_urls_response import MultipartGetPartURLsResponse as MultipartGetPartURLsResponse -from .object_get_summarize_job_response import ObjectGetSummarizeJobResponse as ObjectGetSummarizeJobResponse from .object_create_presigned_url_params import ObjectCreatePresignedURLParams as ObjectCreatePresignedURLParams from .object_create_presigned_url_response import ObjectCreatePresignedURLResponse as ObjectCreatePresignedURLResponse diff --git a/src/casedev/types/vault/graphrag_get_stats_response.py b/src/casedev/types/vault/graphrag_get_stats_response.py deleted file mode 100644 index f390b944..00000000 --- a/src/casedev/types/vault/graphrag_get_stats_response.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["GraphragGetStatsResponse"] - - -class GraphragGetStatsResponse(BaseModel): - communities: Optional[int] = None - """Number of entity communities identified""" - - documents: Optional[int] = None - """Number of processed documents""" - - entities: Optional[int] = None - """Total number of entities extracted from documents""" - - last_processed: Optional[datetime] = FieldInfo(alias="lastProcessed", default=None) - """Timestamp of last GraphRAG processing""" - - relationships: Optional[int] = None - """Total number of relationships between entities""" - - status: Optional[Literal["processing", "completed", "error"]] = None - """Current processing status""" diff --git a/src/casedev/types/vault/graphrag_init_response.py b/src/casedev/types/vault/graphrag_init_response.py deleted file mode 100644 index ef489299..00000000 --- a/src/casedev/types/vault/graphrag_init_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 ..._models import BaseModel - -__all__ = ["GraphragInitResponse"] - - -class GraphragInitResponse(BaseModel): - message: Optional[str] = None - - status: Optional[str] = None - - success: Optional[bool] = None - - vault_id: Optional[str] = None diff --git a/src/casedev/types/vault/graphrag_process_object_response.py b/src/casedev/types/vault/graphrag_process_object_response.py deleted file mode 100644 index d15b21ff..00000000 --- a/src/casedev/types/vault/graphrag_process_object_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["GraphragProcessObjectResponse", "Stats"] - - -class Stats(BaseModel): - """Extraction statistics""" - - community_count: Optional[int] = None - - entity_count: Optional[int] = None - - relationship_count: Optional[int] = None - - -class GraphragProcessObjectResponse(BaseModel): - communities: int - """Number of communities detected""" - - entities: int - """Number of entities extracted""" - - object_id: str = FieldInfo(alias="objectId") - """ID of the indexed object""" - - relationships: int - """Number of relationships extracted""" - - stats: Stats - """Extraction statistics""" - - status: str - """Status from GraphRAG service""" - - success: bool - """Whether indexing completed successfully""" - - vault_id: str = FieldInfo(alias="vaultId") - """ID of the vault""" diff --git a/src/casedev/types/vault/multipart_complete_params.py b/src/casedev/types/vault/multipart_complete_params.py new file mode 100644 index 00000000..a3ec147f --- /dev/null +++ b/src/casedev/types/vault/multipart_complete_params.py @@ -0,0 +1,30 @@ +# 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, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["MultipartCompleteParams", "Part"] + + +class MultipartCompleteParams(TypedDict, total=False): + object_id: Required[Annotated[str, PropertyInfo(alias="objectId")]] + + parts: Required[Iterable[Part]] + + size_bytes: Required[Annotated[int, PropertyInfo(alias="sizeBytes")]] + """File size in bytes (default max 16GB). + + Configure via VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + """ + + upload_id: Required[Annotated[str, PropertyInfo(alias="uploadId")]] + + +class Part(TypedDict, total=False): + etag: Required[str] + + part_number: Required[Annotated[int, PropertyInfo(alias="partNumber")]] diff --git a/src/casedev/types/vault/multipart_init_params.py b/src/casedev/types/vault/multipart_init_params.py new file mode 100644 index 00000000..83dc21a6 --- /dev/null +++ b/src/casedev/types/vault/multipart_init_params.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["MultipartInitParams"] + + +class MultipartInitParams(TypedDict, total=False): + content_type: Required[Annotated[str, PropertyInfo(alias="contentType")]] + """MIME type of the file""" + + filename: Required[str] + """Name of the file to upload""" + + size_bytes: Required[Annotated[int, PropertyInfo(alias="sizeBytes")]] + """File size in bytes (required, default max 16GB). + + Configure via VAULT_MULTIPART_MAX_FILE_SIZE_BYTES. + """ + + auto_index: bool + """Whether to automatically process and index the file for search""" + + is_ai_generated: bool + """Marks the file as AI-generated work product (e.g. + + uploaded by an agent) rather than a user-provided source document. Persisted on + the object and returned by object listings so clients can distinguish + provenance. + """ + + metadata: object + """Additional metadata to associate with the file""" + + part_size_bytes: Annotated[int, PropertyInfo(alias="partSizeBytes")] + """Multipart part size in bytes (min 5MB, max 5GB). Defaults to 64MB.""" + + path: str + """Optional folder path for hierarchy preservation""" diff --git a/src/casedev/types/vault/multipart_init_response.py b/src/casedev/types/vault/multipart_init_response.py new file mode 100644 index 00000000..2ec7c9b6 --- /dev/null +++ b/src/casedev/types/vault/multipart_init_response.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MultipartInitResponse"] + + +class MultipartInitResponse(BaseModel): + next_step: Optional[str] = None + + object_id: Optional[str] = FieldInfo(alias="objectId", default=None) + + part_count: Optional[int] = FieldInfo(alias="partCount", default=None) + + part_size_bytes: Optional[int] = FieldInfo(alias="partSizeBytes", default=None) + + s3_key: Optional[str] = FieldInfo(alias="s3Key", default=None) + + upload_id: Optional[str] = FieldInfo(alias="uploadId", default=None) diff --git a/src/casedev/types/vault/object_append_params.py b/src/casedev/types/vault/object_append_params.py new file mode 100644 index 00000000..5c0f8ac7 --- /dev/null +++ b/src/casedev/types/vault/object_append_params.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["ObjectAppendParams", "Bates"] + + +class ObjectAppendParams(TypedDict, total=False): + id: Required[str] + + append_object_ids: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="appendObjectIds")]] + """Vault object IDs whose pages will be appended onto the target object, in order. + + Must not include the target object itself. + """ + + back_links: Annotated[bool, PropertyInfo(alias="backLinks")] + """Adds back links on appended pages""" + + back_links_text: Annotated[str, PropertyInfo(alias="backLinksText")] + """Label text for the back link. + + Used only when backLinks is true and rendered centered at the bottom of each + appended page. + """ + + bates: Bates + """Optional Bates stamping for appended source PDFs. + + Numbering is deterministic across appendObjectIds order and does not stamp the + target report pages. + """ + + rewrite_links: Annotated[bool, PropertyInfo(alias="rewriteLinks")] + """ + When true, rewrites links in the target object to internal PDF jumps when the + URL contains exactly one appended object ID as a standalone query parameter + value or decoded path segment. + """ + + +class Bates(TypedDict, total=False): + """Optional Bates stamping for appended source PDFs. + + Numbering is deterministic across appendObjectIds order and does not stamp the target report pages. + """ + + enabled: bool + + pad_to: Annotated[int, PropertyInfo(alias="padTo")] + + prefix: str + + start: int + + suffix: str diff --git a/src/casedev/types/vault/object_append_response.py b/src/casedev/types/vault/object_append_response.py new file mode 100644 index 00000000..a9fdf9ff --- /dev/null +++ b/src/casedev/types/vault/object_append_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ObjectAppendResponse"] + + +class ObjectAppendResponse(BaseModel): + id: Optional[str] = None + + bates: Optional[object] = None + + checksum: Optional[str] = None + + content_type: Optional[str] = FieldInfo(alias="contentType", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + download_url: Optional[str] = FieldInfo(alias="downloadUrl", default=None) + + expires_in: Optional[int] = FieldInfo(alias="expiresIn", default=None) + + filename: Optional[str] = None + + ingestion_status: Optional[str] = FieldInfo(alias="ingestionStatus", default=None) + + metadata: Optional[object] = None + + object_id: Optional[str] = FieldInfo(alias="objectId", default=None) + + page_count: Optional[int] = FieldInfo(alias="pageCount", default=None) + + size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None) + + vault_id: Optional[str] = FieldInfo(alias="vaultId", default=None) diff --git a/src/casedev/types/vault/object_get_summarize_job_response.py b/src/casedev/types/vault/object_get_summarize_job_response.py deleted file mode 100644 index d57770f9..00000000 --- a/src/casedev/types/vault/object_get_summarize_job_response.py +++ /dev/null @@ -1,40 +0,0 @@ -# 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 pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["ObjectGetSummarizeJobResponse"] - - -class ObjectGetSummarizeJobResponse(BaseModel): - completed_at: Optional[datetime] = FieldInfo(alias="completedAt", default=None) - """When the job completed""" - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - """When the job was created""" - - error: Optional[str] = None - """Error message (if failed)""" - - job_id: Optional[str] = FieldInfo(alias="jobId", default=None) - """Case.dev job ID""" - - result_filename: Optional[str] = FieldInfo(alias="resultFilename", default=None) - """Filename of the result document (if completed)""" - - result_object_id: Optional[str] = FieldInfo(alias="resultObjectId", default=None) - """ID of the result document (if completed)""" - - source_object_id: Optional[str] = FieldInfo(alias="sourceObjectId", default=None) - """ID of the source document""" - - status: Optional[Literal["pending", "processing", "completed", "failed"]] = None - """Current job status""" - - workflow_type: Optional[str] = FieldInfo(alias="workflowType", default=None) - """Type of workflow being executed""" diff --git a/src/casedev/types/vault/object_list_params.py b/src/casedev/types/vault/object_list_params.py new file mode 100644 index 00000000..76d13deb --- /dev/null +++ b/src/casedev/types/vault/object_list_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 Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ObjectListParams"] + + +class ObjectListParams(TypedDict, total=False): + include_unconfirmed: Annotated[bool, PropertyInfo(alias="includeUnconfirmed")] + """ + Include placeholders for uploads that were never completed (awaiting_upload) or + were cancelled (aborted). Excluded by default. + """ diff --git a/src/casedev/types/vault/object_list_response.py b/src/casedev/types/vault/object_list_response.py index c057ee51..8e350e94 100644 --- a/src/casedev/types/vault/object_list_response.py +++ b/src/casedev/types/vault/object_list_response.py @@ -41,6 +41,9 @@ class Object(BaseModel): ingestion_workflow_id: Optional[str] = FieldInfo(alias="ingestionWorkflowId", default=None) """Durable workflow run ID for the active or last ingestion attempt""" + is_ai_generated: Optional[bool] = None + """Whether the file was marked as AI-generated work product at upload time""" + metadata: Optional[object] = None """Custom metadata associated with the document""" diff --git a/src/casedev/types/vault/object_merge_params.py b/src/casedev/types/vault/object_merge_params.py new file mode 100644 index 00000000..a0f3d6d9 --- /dev/null +++ b/src/casedev/types/vault/object_merge_params.py @@ -0,0 +1,36 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["ObjectMergeParams", "Bates"] + + +class ObjectMergeParams(TypedDict, total=False): + filename: Required[str] + """Output PDF filename""" + + source_object_ids: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="sourceObjectIds")]] + """Source object IDs in output order""" + + source_rendition: Required[Annotated[Literal["original", "searchable_pdf"], PropertyInfo(alias="sourceRendition")]] + + idempotency_key: Required[Annotated[str, PropertyInfo(alias="Idempotency-Key")]] + + bates: Bates + + client_reference: Annotated[str, PropertyInfo(alias="clientReference")] + + +class Bates(TypedDict, total=False): + pad_to: Annotated[int, PropertyInfo(alias="padTo")] + + prefix: str + + start: int + + suffix: str diff --git a/src/casedev/types/vault/object_merge_response.py b/src/casedev/types/vault/object_merge_response.py new file mode 100644 index 00000000..65704223 --- /dev/null +++ b/src/casedev/types/vault/object_merge_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["ObjectMergeResponse"] + + +class ObjectMergeResponse(BaseModel): + client_reference: Optional[str] = FieldInfo(alias="clientReference", default=None) + + object_id: Optional[str] = FieldInfo(alias="objectId", default=None) + + status: Optional[Literal["processing"]] = None + + workflow_id: Optional[str] = FieldInfo(alias="workflowId", default=None) diff --git a/src/casedev/types/vault/object_retrieve_response.py b/src/casedev/types/vault/object_retrieve_response.py index 72eeccc8..df9be6bf 100644 --- a/src/casedev/types/vault/object_retrieve_response.py +++ b/src/casedev/types/vault/object_retrieve_response.py @@ -41,6 +41,9 @@ class ObjectRetrieveResponse(BaseModel): ingestion_error: Optional[str] = FieldInfo(alias="ingestionError", default=None) """Error details when ingestion fails""" + is_ai_generated: Optional[bool] = None + """Whether the file was marked as AI-generated work product at upload time""" + metadata: Optional[object] = None """Additional metadata""" diff --git a/src/casedev/types/vault_confirm_upload_params.py b/src/casedev/types/vault_confirm_upload_params.py index f71b18a5..9d684c4e 100644 --- a/src/casedev/types/vault_confirm_upload_params.py +++ b/src/casedev/types/vault_confirm_upload_params.py @@ -2,38 +2,38 @@ from __future__ import annotations -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._utils import PropertyInfo -__all__ = ["VaultConfirmUploadParams", "VaultConfirmUploadSuccess", "VaultConfirmUploadFailure"] +__all__ = ["VaultConfirmUploadParams"] -class VaultConfirmUploadSuccess(TypedDict, total=False): +class VaultConfirmUploadParams(TypedDict, total=False): id: Required[str] - size_bytes: Required[Annotated[int, PropertyInfo(alias="sizeBytes")]] - """Uploaded file size in bytes""" - - success: Required[Literal[True]] + success: Required[bool] """Whether the upload succeeded""" - etag: str - """S3 ETag for the uploaded object (optional if client cannot access ETag header)""" - + auto_ingest: Annotated[bool, PropertyInfo(alias="autoIngest")] + """ + When true and the object was uploaded with auto_index, trigger ingestion + immediately after a successful confirmation (no separate ingest call needed). + The ingest outcome is reported in the `ingest` response field; an ingest failure + does not fail the confirmation. + """ -class VaultConfirmUploadFailure(TypedDict, total=False): - id: Required[str] + error_code: Annotated[str, PropertyInfo(alias="errorCode")] + """Client-side error code. Required when success=false.""" - error_code: Required[Annotated[str, PropertyInfo(alias="errorCode")]] - """Client-side error code""" + error_message: Annotated[str, PropertyInfo(alias="errorMessage")] + """Client-side error message. Required when success=false.""" - error_message: Required[Annotated[str, PropertyInfo(alias="errorMessage")]] - """Client-side error message""" - - success: Required[Literal[False]] - """Whether the upload succeeded""" + etag: str + """S3 ETag for the uploaded object (optional if client cannot access ETag header). + Only meaningful when success=true. + """ -VaultConfirmUploadParams: TypeAlias = Union[VaultConfirmUploadSuccess, VaultConfirmUploadFailure] + size_bytes: Annotated[int, PropertyInfo(alias="sizeBytes")] + """Uploaded file size in bytes. Required when success=true.""" diff --git a/src/casedev/types/vault_confirm_upload_response.py b/src/casedev/types/vault_confirm_upload_response.py index 697110ca..0c790222 100644 --- a/src/casedev/types/vault_confirm_upload_response.py +++ b/src/casedev/types/vault_confirm_upload_response.py @@ -7,12 +7,25 @@ from .._models import BaseModel -__all__ = ["VaultConfirmUploadResponse"] +__all__ = ["VaultConfirmUploadResponse", "Ingest"] + + +class Ingest(BaseModel): + """Present when autoIngest was requested on a successful confirmation""" + + error: Optional[str] = None + + triggered: Optional[bool] = None + + workflow_id: Optional[str] = FieldInfo(alias="workflowId", default=None) class VaultConfirmUploadResponse(BaseModel): already_confirmed: Optional[bool] = FieldInfo(alias="alreadyConfirmed", default=None) + ingest: Optional[Ingest] = None + """Present when autoIngest was requested on a successful confirmation""" + object_id: Optional[str] = FieldInfo(alias="objectId", default=None) status: Optional[Literal["completed", "failed"]] = None diff --git a/src/casedev/types/vault_ingest_response.py b/src/casedev/types/vault_ingest_response.py index 454bf75c..0d3ffff8 100644 --- a/src/casedev/types/vault_ingest_response.py +++ b/src/casedev/types/vault_ingest_response.py @@ -12,10 +12,7 @@ class VaultIngestResponse(BaseModel): enable_graph_rag: bool = FieldInfo(alias="enableGraphRAG") - """ - Always false - GraphRAG must be triggered separately via POST - /vault/:id/graphrag/:objectId - """ + """Always false; retained for response compatibility""" message: str """Human-readable status message""" diff --git a/src/casedev/types/vault_search_params.py b/src/casedev/types/vault_search_params.py index 72c708e0..b3264eb3 100644 --- a/src/casedev/types/vault_search_params.py +++ b/src/casedev/types/vault_search_params.py @@ -31,7 +31,11 @@ class VaultSearchParams(TypedDict, total=False): """ -class Filters(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] +class Filters( # type: ignore[call-arg] + TypedDict, + total=False, + extra_items=object, # pyright: ignore[reportGeneralTypeIssues] +): """Filters to narrow search results to specific documents""" object_id: Union[str, SequenceNotStr[str]] diff --git a/src/casedev/types/vault_upload_params.py b/src/casedev/types/vault_upload_params.py index d3bcdcc1..af2e9f6e 100644 --- a/src/casedev/types/vault_upload_params.py +++ b/src/casedev/types/vault_upload_params.py @@ -19,6 +19,14 @@ class VaultUploadParams(TypedDict, total=False): auto_index: bool """Whether to automatically process and index the file for search""" + is_ai_generated: bool + """Marks the file as AI-generated work product (e.g. + + uploaded by an agent) rather than a user-provided source document. Persisted on + the object and returned by object listings so clients can distinguish + provenance. + """ + metadata: object """Additional metadata to associate with the file""" @@ -34,3 +42,5 @@ class VaultUploadParams(TypedDict, total=False): When provided, enforces exact file size at S3 level. """ + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] diff --git a/src/casedev/types/vault_upload_response.py b/src/casedev/types/vault_upload_response.py index d4ae7fa1..6b97a741 100644 --- a/src/casedev/types/vault_upload_response.py +++ b/src/casedev/types/vault_upload_response.py @@ -18,6 +18,9 @@ class Instructions(BaseModel): class VaultUploadResponse(BaseModel): + already_uploaded: Optional[bool] = FieldInfo(alias="alreadyUploaded", default=None) + """True when this idempotency key already identifies a confirmed upload""" + auto_index: Optional[bool] = None """Whether the file will be automatically indexed""" @@ -29,6 +32,9 @@ class VaultUploadResponse(BaseModel): instructions: Optional[Instructions] = None + is_ai_generated: Optional[bool] = None + """Whether the file is marked as AI-generated work product""" + next_step: Optional[str] = None """Next API endpoint to call for processing""" diff --git a/src/casedev/types/voice/transcription_create_response.py b/src/casedev/types/voice/transcription_create_response.py index 20fee025..2430b802 100644 --- a/src/casedev/types/voice/transcription_create_response.py +++ b/src/casedev/types/voice/transcription_create_response.py @@ -12,10 +12,16 @@ class TranscriptionCreateResponse(BaseModel): id: Optional[str] = None """Unique transcription job ID""" + input_object_id: Optional[str] = None + """Object submitted to the speech provider. + + For large videos, this is an internal audio derivative. + """ + source_object_id: Optional[str] = None - """Source audio object ID (only for vault-based transcription)""" + """Original source media object ID (only for vault-based transcription)""" - status: Optional[Literal["queued", "processing", "completed", "error"]] = None + status: Optional[Literal["queued", "preprocessing", "processing", "completed", "error"]] = None """Current status of the transcription job""" vault_id: Optional[str] = None diff --git a/src/casedev/types/voice/transcription_retrieve_response.py b/src/casedev/types/voice/transcription_retrieve_response.py index a50dc146..66ff4d4e 100644 --- a/src/casedev/types/voice/transcription_retrieve_response.py +++ b/src/casedev/types/voice/transcription_retrieve_response.py @@ -12,7 +12,7 @@ class TranscriptionRetrieveResponse(BaseModel): id: str """Unique transcription job ID""" - status: Literal["queued", "processing", "completed", "failed"] + status: Literal["queued", "preprocessing", "processing", "completed", "failed"] """Current status of the transcription job""" audio_duration: Optional[float] = None @@ -24,11 +24,17 @@ class TranscriptionRetrieveResponse(BaseModel): error: Optional[str] = None """Error message (only present when status is failed)""" + input_object_id: Optional[str] = None + """Media object submitted to the speech provider. + + May be an internal audio derivative for large videos. + """ + result_object_id: Optional[str] = None """Result transcript object ID (vault-based jobs, when completed)""" source_object_id: Optional[str] = None - """Source audio object ID (vault-based jobs only)""" + """Original source media object ID (vault-based jobs only)""" text: Optional[str] = None """ diff --git a/tests/api_resources/agent/v1/test_agents.py b/tests/api_resources/agent/v1/test_agents.py deleted file mode 100644 index 91ce447a..00000000 --- a/tests/api_resources/agent/v1/test_agents.py +++ /dev/null @@ -1,460 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.agent.v1 import ( - AgentListResponse, - AgentCreateResponse, - AgentDeleteResponse, - AgentUpdateResponse, - AgentRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAgents: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - agent = client.agent.v1.agents.create( - instructions="instructions", - name="name", - ) - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - agent = client.agent.v1.agents.create( - instructions="instructions", - name="name", - description="description", - disabled_tools=["string"], - enabled_tools=["string"], - model="model", - sandbox={ - "cpu": 0, - "memory_mi_b": 0, - }, - vault_groups=["string"], - vault_ids=["string"], - ) - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.agent.v1.agents.with_raw_response.create( - instructions="instructions", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = response.parse() - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.agent.v1.agents.with_streaming_response.create( - instructions="instructions", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = response.parse() - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Casedev) -> None: - agent = client.agent.v1.agents.retrieve( - "id", - ) - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Casedev) -> None: - response = client.agent.v1.agents.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = response.parse() - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Casedev) -> None: - with client.agent.v1.agents.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = response.parse() - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.agents.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Casedev) -> None: - agent = client.agent.v1.agents.update( - id="id", - ) - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Casedev) -> None: - agent = client.agent.v1.agents.update( - id="id", - description="description", - disabled_tools=["string"], - enabled_tools=["string"], - instructions="instructions", - model="model", - name="name", - sandbox={}, - vault_groups=["string"], - vault_ids=["string"], - ) - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Casedev) -> None: - response = client.agent.v1.agents.with_raw_response.update( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = response.parse() - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Casedev) -> None: - with client.agent.v1.agents.with_streaming_response.update( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = response.parse() - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.agents.with_raw_response.update( - id="", - ) - - @parametrize - def test_method_list(self, client: Casedev) -> None: - agent = client.agent.v1.agents.list() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Casedev) -> None: - agent = client.agent.v1.agents.list( - cursor="cursor", - limit=1, - ) - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Casedev) -> None: - response = client.agent.v1.agents.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = response.parse() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Casedev) -> None: - with client.agent.v1.agents.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = response.parse() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Casedev) -> None: - agent = client.agent.v1.agents.delete( - "id", - ) - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Casedev) -> None: - response = client.agent.v1.agents.with_raw_response.delete( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = response.parse() - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Casedev) -> None: - with client.agent.v1.agents.with_streaming_response.delete( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = response.parse() - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.agents.with_raw_response.delete( - "", - ) - - -class TestAsyncAgents: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.create( - instructions="instructions", - name="name", - ) - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.create( - instructions="instructions", - name="name", - description="description", - disabled_tools=["string"], - enabled_tools=["string"], - model="model", - sandbox={ - "cpu": 0, - "memory_mi_b": 0, - }, - vault_groups=["string"], - vault_ids=["string"], - ) - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.agents.with_raw_response.create( - instructions="instructions", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = await response.parse() - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.agents.with_streaming_response.create( - instructions="instructions", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = await response.parse() - assert_matches_type(AgentCreateResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.retrieve( - "id", - ) - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.agents.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = await response.parse() - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.agents.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = await response.parse() - assert_matches_type(AgentRetrieveResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.agents.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.update( - id="id", - ) - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.update( - id="id", - description="description", - disabled_tools=["string"], - enabled_tools=["string"], - instructions="instructions", - model="model", - name="name", - sandbox={}, - vault_groups=["string"], - vault_ids=["string"], - ) - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.agents.with_raw_response.update( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = await response.parse() - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.agents.with_streaming_response.update( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = await response.parse() - assert_matches_type(AgentUpdateResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.agents.with_raw_response.update( - id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.list() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.list( - cursor="cursor", - limit=1, - ) - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.agents.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = await response.parse() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.agents.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = await response.parse() - assert_matches_type(AgentListResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncCasedev) -> None: - agent = await async_client.agent.v1.agents.delete( - "id", - ) - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.agents.with_raw_response.delete( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - agent = await response.parse() - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.agents.with_streaming_response.delete( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - agent = await response.parse() - assert_matches_type(AgentDeleteResponse, agent, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.agents.with_raw_response.delete( - "", - ) diff --git a/tests/api_resources/agent/v1/test_execute.py b/tests/api_resources/agent/v1/test_execute.py deleted file mode 100644 index 6a1e4370..00000000 --- a/tests/api_resources/agent/v1/test_execute.py +++ /dev/null @@ -1,122 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.agent.v1 import ExecuteCreateResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestExecute: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - execute = client.agent.v1.execute.create( - prompt="prompt", - ) - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - execute = client.agent.v1.execute.create( - prompt="prompt", - disabled_tools=["string"], - enabled_tools=["string"], - guidance="guidance", - instructions="instructions", - model="model", - object_ids=["string"], - sandbox={ - "cpu": 0, - "memory_mi_b": 0, - }, - vault_ids=["string"], - ) - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.agent.v1.execute.with_raw_response.create( - prompt="prompt", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - execute = response.parse() - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.agent.v1.execute.with_streaming_response.create( - prompt="prompt", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - execute = response.parse() - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncExecute: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - execute = await async_client.agent.v1.execute.create( - prompt="prompt", - ) - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - execute = await async_client.agent.v1.execute.create( - prompt="prompt", - disabled_tools=["string"], - enabled_tools=["string"], - guidance="guidance", - instructions="instructions", - model="model", - object_ids=["string"], - sandbox={ - "cpu": 0, - "memory_mi_b": 0, - }, - vault_ids=["string"], - ) - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.execute.with_raw_response.create( - prompt="prompt", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - execute = await response.parse() - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.execute.with_streaming_response.create( - prompt="prompt", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - execute = await response.parse() - assert_matches_type(ExecuteCreateResponse, execute, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/agent/v1/test_run.py b/tests/api_resources/agent/v1/test_run.py deleted file mode 100644 index 902153a1..00000000 --- a/tests/api_resources/agent/v1/test_run.py +++ /dev/null @@ -1,672 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.agent.v1 import ( - RunExecResponse, - RunListResponse, - RunWatchResponse, - RunCancelResponse, - RunCreateResponse, - RunGetStatusResponse, - RunGetDetailsResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRun: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - run = client.agent.v1.run.create( - agent_id="agentId", - prompt="prompt", - ) - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - run = client.agent.v1.run.create( - agent_id="agentId", - prompt="prompt", - callback_url="https://example.com", - guidance="guidance", - model="model", - object_ids=["string"], - ) - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.create( - agent_id="agentId", - prompt="prompt", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.create( - agent_id="agentId", - prompt="prompt", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunCreateResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Casedev) -> None: - run = client.agent.v1.run.list() - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Casedev) -> None: - run = client.agent.v1.run.list( - agent_id="agentId", - cursor="cursor", - limit=1, - status="queued", - ) - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunListResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_cancel(self, client: Casedev) -> None: - run = client.agent.v1.run.cancel( - "id", - ) - assert_matches_type(RunCancelResponse, run, path=["response"]) - - @parametrize - def test_raw_response_cancel(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.cancel( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunCancelResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_cancel(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.cancel( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunCancelResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_cancel(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.cancel( - "", - ) - - @parametrize - def test_method_events(self, client: Casedev) -> None: - run_stream = client.agent.v1.run.events( - id="id", - ) - run_stream.response.close() - - @parametrize - def test_method_events_with_all_params(self, client: Casedev) -> None: - run_stream = client.agent.v1.run.events( - id="id", - last_event_id=0, - ) - run_stream.response.close() - - @parametrize - def test_raw_response_events(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.events( - id="id", - ) - - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = response.parse() - stream.close() - - @parametrize - def test_streaming_response_events(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.events( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = response.parse() - stream.close() - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_events(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.events( - id="", - ) - - @parametrize - def test_method_exec(self, client: Casedev) -> None: - run = client.agent.v1.run.exec( - "id", - ) - assert_matches_type(RunExecResponse, run, path=["response"]) - - @parametrize - def test_raw_response_exec(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.exec( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunExecResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_exec(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.exec( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunExecResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_exec(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.exec( - "", - ) - - @parametrize - def test_method_get_details(self, client: Casedev) -> None: - run = client.agent.v1.run.get_details( - "id", - ) - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - @parametrize - def test_raw_response_get_details(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.get_details( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_get_details(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.get_details( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_details(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.get_details( - "", - ) - - @parametrize - def test_method_get_status(self, client: Casedev) -> None: - run = client.agent.v1.run.get_status( - "id", - ) - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - @parametrize - def test_raw_response_get_status(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.get_status( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_get_status(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.get_status( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_status(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.get_status( - "", - ) - - @parametrize - def test_method_watch(self, client: Casedev) -> None: - run = client.agent.v1.run.watch( - id="id", - callback_url="https://example.com", - ) - assert_matches_type(RunWatchResponse, run, path=["response"]) - - @parametrize - def test_raw_response_watch(self, client: Casedev) -> None: - response = client.agent.v1.run.with_raw_response.watch( - id="id", - callback_url="https://example.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = response.parse() - assert_matches_type(RunWatchResponse, run, path=["response"]) - - @parametrize - def test_streaming_response_watch(self, client: Casedev) -> None: - with client.agent.v1.run.with_streaming_response.watch( - id="id", - callback_url="https://example.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = response.parse() - assert_matches_type(RunWatchResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_watch(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.agent.v1.run.with_raw_response.watch( - id="", - callback_url="https://example.com", - ) - - -class TestAsyncRun: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.create( - agent_id="agentId", - prompt="prompt", - ) - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.create( - agent_id="agentId", - prompt="prompt", - callback_url="https://example.com", - guidance="guidance", - model="model", - object_ids=["string"], - ) - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.create( - agent_id="agentId", - prompt="prompt", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunCreateResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.create( - agent_id="agentId", - prompt="prompt", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunCreateResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.list() - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.list( - agent_id="agentId", - cursor="cursor", - limit=1, - status="queued", - ) - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunListResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunListResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_cancel(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.cancel( - "id", - ) - assert_matches_type(RunCancelResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_cancel(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.cancel( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunCancelResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_cancel(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.cancel( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunCancelResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_cancel(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.cancel( - "", - ) - - @parametrize - async def test_method_events(self, async_client: AsyncCasedev) -> None: - run_stream = await async_client.agent.v1.run.events( - id="id", - ) - await run_stream.response.aclose() - - @parametrize - async def test_method_events_with_all_params(self, async_client: AsyncCasedev) -> None: - run_stream = await async_client.agent.v1.run.events( - id="id", - last_event_id=0, - ) - await run_stream.response.aclose() - - @parametrize - async def test_raw_response_events(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.events( - id="id", - ) - - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = await response.parse() - await stream.close() - - @parametrize - async def test_streaming_response_events(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.events( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = await response.parse() - await stream.close() - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_events(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.events( - id="", - ) - - @parametrize - async def test_method_exec(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.exec( - "id", - ) - assert_matches_type(RunExecResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_exec(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.exec( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunExecResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_exec(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.exec( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunExecResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_exec(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.exec( - "", - ) - - @parametrize - async def test_method_get_details(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.get_details( - "id", - ) - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_get_details(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.get_details( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_get_details(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.get_details( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunGetDetailsResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_details(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.get_details( - "", - ) - - @parametrize - async def test_method_get_status(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.get_status( - "id", - ) - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_get_status(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.get_status( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_get_status(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.get_status( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunGetStatusResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_status(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.get_status( - "", - ) - - @parametrize - async def test_method_watch(self, async_client: AsyncCasedev) -> None: - run = await async_client.agent.v1.run.watch( - id="id", - callback_url="https://example.com", - ) - assert_matches_type(RunWatchResponse, run, path=["response"]) - - @parametrize - async def test_raw_response_watch(self, async_client: AsyncCasedev) -> None: - response = await async_client.agent.v1.run.with_raw_response.watch( - id="id", - callback_url="https://example.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - run = await response.parse() - assert_matches_type(RunWatchResponse, run, path=["response"]) - - @parametrize - async def test_streaming_response_watch(self, async_client: AsyncCasedev) -> None: - async with async_client.agent.v1.run.with_streaming_response.watch( - id="id", - callback_url="https://example.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - run = await response.parse() - assert_matches_type(RunWatchResponse, run, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_watch(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.agent.v1.run.with_raw_response.watch( - id="", - callback_url="https://example.com", - ) diff --git a/tests/api_resources/agent/__init__.py b/tests/api_resources/connectors/__init__.py similarity index 100% rename from tests/api_resources/agent/__init__.py rename to tests/api_resources/connectors/__init__.py diff --git a/tests/api_resources/connectors/test_v1.py b/tests/api_resources/connectors/test_v1.py new file mode 100644 index 00000000..c74c3ae3 --- /dev/null +++ b/tests/api_resources/connectors/test_v1.py @@ -0,0 +1,282 @@ +# 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 casedev import Casedev, AsyncCasedev +from tests.utils import assert_matches_type +from casedev.types.connectors import V1SyncLinkResponse, V1TransferResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestV1: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_sync_link(self, client: Casedev) -> None: + v1 = client.connectors.v1.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + def test_method_sync_link_with_all_params(self, client: Casedev) -> None: + v1 = client.connectors.v1.sync_link( + connection_id="connection_id", + direction="import", + remote={ + "folder_id": "folder_id", + "container_id": "container_id", + "path": "path", + "site_id": "site_id", + }, + vault_id="vault_id", + matter_id="matter_id", + policy={ + "collisions": "version", + "deletes": "mirror", + "filters": { + "exclude_mime": ["string"], + "max_size_bytes": 0, + }, + }, + ) + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + def test_raw_response_sync_link(self, client: Casedev) -> None: + response = client.connectors.v1.with_raw_response.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = response.parse() + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + def test_streaming_response_sync_link(self, client: Casedev) -> None: + with client.connectors.v1.with_streaming_response.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = response.parse() + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_transfer(self, client: Casedev) -> None: + v1 = client.connectors.v1.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + def test_method_transfer_with_all_params(self, client: Casedev) -> None: + v1 = client.connectors.v1.transfer( + connection_id="connection_id", + direction="import", + remote={ + "folder_id": "folder_id", + "container_id": "container_id", + "path": "path", + "site_id": "site_id", + }, + vault_id="vault_id", + matter_id="matter_id", + policy={ + "collisions": "version", + "deletes": "mirror", + "filters": { + "exclude_mime": ["string"], + "max_size_bytes": 0, + }, + }, + run_mode="auto", + ) + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + def test_raw_response_transfer(self, client: Casedev) -> None: + response = client.connectors.v1.with_raw_response.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = response.parse() + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + def test_streaming_response_transfer(self, client: Casedev) -> None: + with client.connectors.v1.with_streaming_response.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = response.parse() + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncV1: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_sync_link(self, async_client: AsyncCasedev) -> None: + v1 = await async_client.connectors.v1.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + async def test_method_sync_link_with_all_params(self, async_client: AsyncCasedev) -> None: + v1 = await async_client.connectors.v1.sync_link( + connection_id="connection_id", + direction="import", + remote={ + "folder_id": "folder_id", + "container_id": "container_id", + "path": "path", + "site_id": "site_id", + }, + vault_id="vault_id", + matter_id="matter_id", + policy={ + "collisions": "version", + "deletes": "mirror", + "filters": { + "exclude_mime": ["string"], + "max_size_bytes": 0, + }, + }, + ) + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + async def test_raw_response_sync_link(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.with_raw_response.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = await response.parse() + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + @parametrize + async def test_streaming_response_sync_link(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.with_streaming_response.sync_link( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = await response.parse() + assert_matches_type(V1SyncLinkResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_transfer(self, async_client: AsyncCasedev) -> None: + v1 = await async_client.connectors.v1.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + async def test_method_transfer_with_all_params(self, async_client: AsyncCasedev) -> None: + v1 = await async_client.connectors.v1.transfer( + connection_id="connection_id", + direction="import", + remote={ + "folder_id": "folder_id", + "container_id": "container_id", + "path": "path", + "site_id": "site_id", + }, + vault_id="vault_id", + matter_id="matter_id", + policy={ + "collisions": "version", + "deletes": "mirror", + "filters": { + "exclude_mime": ["string"], + "max_size_bytes": 0, + }, + }, + run_mode="auto", + ) + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + async def test_raw_response_transfer(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.with_raw_response.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + v1 = await response.parse() + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + @parametrize + async def test_streaming_response_transfer(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.with_streaming_response.transfer( + connection_id="connection_id", + direction="import", + remote={"folder_id": "folder_id"}, + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + v1 = await response.parse() + assert_matches_type(V1TransferResponse, v1, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/agent/v1/__init__.py b/tests/api_resources/connectors/v1/__init__.py similarity index 100% rename from tests/api_resources/agent/v1/__init__.py rename to tests/api_resources/connectors/v1/__init__.py diff --git a/tests/api_resources/database/__init__.py b/tests/api_resources/connectors/v1/installations/__init__.py similarity index 100% rename from tests/api_resources/database/__init__.py rename to tests/api_resources/connectors/v1/installations/__init__.py diff --git a/tests/api_resources/connectors/v1/installations/test_vaults.py b/tests/api_resources/connectors/v1/installations/test_vaults.py new file mode 100644 index 00000000..00855920 --- /dev/null +++ b/tests/api_resources/connectors/v1/installations/test_vaults.py @@ -0,0 +1,316 @@ +# 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 casedev import Casedev, AsyncCasedev + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVaults: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Casedev) -> None: + vault = client.connectors.v1.installations.vaults.list( + "id", + ) + assert vault is None + + @parametrize + def test_raw_response_list(self, client: Casedev) -> None: + response = client.connectors.v1.installations.vaults.with_raw_response.list( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert vault is None + + @parametrize + def test_streaming_response_list(self, client: Casedev) -> None: + with client.connectors.v1.installations.vaults.with_streaming_response.list( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.installations.vaults.with_raw_response.list( + "", + ) + + @parametrize + def test_method_grant(self, client: Casedev) -> None: + vault = client.connectors.v1.installations.vaults.grant( + vault_id="vaultId", + id="id", + ) + assert vault is None + + @parametrize + def test_method_grant_with_all_params(self, client: Casedev) -> None: + vault = client.connectors.v1.installations.vaults.grant( + vault_id="vaultId", + id="id", + can_manage=True, + can_read=True, + can_write=True, + relationship="owned", + source="provisioning", + ) + assert vault is None + + @parametrize + def test_raw_response_grant(self, client: Casedev) -> None: + response = client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="vaultId", + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert vault is None + + @parametrize + def test_streaming_response_grant(self, client: Casedev) -> None: + with client.connectors.v1.installations.vaults.with_streaming_response.grant( + vault_id="vaultId", + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_grant(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="vaultId", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vault_id` but received ''"): + client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="", + id="id", + ) + + @parametrize + def test_method_revoke(self, client: Casedev) -> None: + vault = client.connectors.v1.installations.vaults.revoke( + vault_id="vaultId", + id="id", + ) + assert vault is None + + @parametrize + def test_raw_response_revoke(self, client: Casedev) -> None: + response = client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="vaultId", + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert vault is None + + @parametrize + def test_streaming_response_revoke(self, client: Casedev) -> None: + with client.connectors.v1.installations.vaults.with_streaming_response.revoke( + vault_id="vaultId", + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_revoke(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="vaultId", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vault_id` but received ''"): + client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="", + id="id", + ) + + +class TestAsyncVaults: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCasedev) -> None: + vault = await async_client.connectors.v1.installations.vaults.list( + "id", + ) + assert vault is None + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.installations.vaults.with_raw_response.list( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert vault is None + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.installations.vaults.with_streaming_response.list( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.installations.vaults.with_raw_response.list( + "", + ) + + @parametrize + async def test_method_grant(self, async_client: AsyncCasedev) -> None: + vault = await async_client.connectors.v1.installations.vaults.grant( + vault_id="vaultId", + id="id", + ) + assert vault is None + + @parametrize + async def test_method_grant_with_all_params(self, async_client: AsyncCasedev) -> None: + vault = await async_client.connectors.v1.installations.vaults.grant( + vault_id="vaultId", + id="id", + can_manage=True, + can_read=True, + can_write=True, + relationship="owned", + source="provisioning", + ) + assert vault is None + + @parametrize + async def test_raw_response_grant(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="vaultId", + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert vault is None + + @parametrize + async def test_streaming_response_grant(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.installations.vaults.with_streaming_response.grant( + vault_id="vaultId", + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_grant(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="vaultId", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vault_id` but received ''"): + await async_client.connectors.v1.installations.vaults.with_raw_response.grant( + vault_id="", + id="id", + ) + + @parametrize + async def test_method_revoke(self, async_client: AsyncCasedev) -> None: + vault = await async_client.connectors.v1.installations.vaults.revoke( + vault_id="vaultId", + id="id", + ) + assert vault is None + + @parametrize + async def test_raw_response_revoke(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="vaultId", + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert vault is None + + @parametrize + async def test_streaming_response_revoke(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.installations.vaults.with_streaming_response.revoke( + vault_id="vaultId", + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_revoke(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="vaultId", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `vault_id` but received ''"): + await async_client.connectors.v1.installations.vaults.with_raw_response.revoke( + vault_id="", + id="id", + ) diff --git a/tests/api_resources/connectors/v1/test_connections.py b/tests/api_resources/connectors/v1/test_connections.py new file mode 100644 index 00000000..b434fc17 --- /dev/null +++ b/tests/api_resources/connectors/v1/test_connections.py @@ -0,0 +1,450 @@ +# 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 casedev import Casedev, AsyncCasedev +from tests.utils import assert_matches_type +from casedev.types.connectors.v1 import ( + ConnectionListResponse, + ConnectionBrowseResponse, + ConnectionCreateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConnections: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.create( + provider="clio", + return_url="return_url", + ) + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.create( + provider="clio", + return_url="return_url", + scope_tier="clio.us", + ) + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Casedev) -> None: + response = client.connectors.v1.connections.with_raw_response.create( + provider="clio", + return_url="return_url", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Casedev) -> None: + with client.connectors.v1.connections.with_streaming_response.create( + provider="clio", + return_url="return_url", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.retrieve( + "id", + ) + assert connection is None + + @parametrize + def test_raw_response_retrieve(self, client: Casedev) -> None: + response = client.connectors.v1.connections.with_raw_response.retrieve( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert connection is None + + @parametrize + def test_streaming_response_retrieve(self, client: Casedev) -> None: + with client.connectors.v1.connections.with_streaming_response.retrieve( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert connection is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.connections.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.list() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.list( + provider="provider", + status="pending", + ) + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Casedev) -> None: + response = client.connectors.v1.connections.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Casedev) -> None: + with client.connectors.v1.connections.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.delete( + id="id", + ) + assert connection is None + + @parametrize + def test_method_delete_with_all_params(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.delete( + id="id", + purge=True, + ) + assert connection is None + + @parametrize + def test_raw_response_delete(self, client: Casedev) -> None: + response = client.connectors.v1.connections.with_raw_response.delete( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert connection is None + + @parametrize + def test_streaming_response_delete(self, client: Casedev) -> None: + with client.connectors.v1.connections.with_streaming_response.delete( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert connection is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.connections.with_raw_response.delete( + id="", + ) + + @parametrize + def test_method_browse(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.browse( + id="id", + ) + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + def test_method_browse_with_all_params(self, client: Casedev) -> None: + connection = client.connectors.v1.connections.browse( + id="id", + container="container", + cursor="cursor", + page_size=1000, + parent="parent", + query="query", + site="site", + ) + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + def test_raw_response_browse(self, client: Casedev) -> None: + response = client.connectors.v1.connections.with_raw_response.browse( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = response.parse() + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + def test_streaming_response_browse(self, client: Casedev) -> None: + with client.connectors.v1.connections.with_streaming_response.browse( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = response.parse() + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_browse(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.connections.with_raw_response.browse( + id="", + ) + + +class TestAsyncConnections: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.create( + provider="clio", + return_url="return_url", + ) + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.create( + provider="clio", + return_url="return_url", + scope_tier="clio.us", + ) + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.connections.with_raw_response.create( + provider="clio", + return_url="return_url", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.connections.with_streaming_response.create( + provider="clio", + return_url="return_url", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert_matches_type(ConnectionCreateResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.retrieve( + "id", + ) + assert connection is None + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.connections.with_raw_response.retrieve( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert connection is None + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.connections.with_streaming_response.retrieve( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert connection is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.connections.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.list() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.list( + provider="provider", + status="pending", + ) + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.connections.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.connections.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert_matches_type(ConnectionListResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.delete( + id="id", + ) + assert connection is None + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.delete( + id="id", + purge=True, + ) + assert connection is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.connections.with_raw_response.delete( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert connection is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.connections.with_streaming_response.delete( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert connection is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.connections.with_raw_response.delete( + id="", + ) + + @parametrize + async def test_method_browse(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.browse( + id="id", + ) + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + async def test_method_browse_with_all_params(self, async_client: AsyncCasedev) -> None: + connection = await async_client.connectors.v1.connections.browse( + id="id", + container="container", + cursor="cursor", + page_size=1000, + parent="parent", + query="query", + site="site", + ) + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + async def test_raw_response_browse(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.connections.with_raw_response.browse( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + connection = await response.parse() + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + @parametrize + async def test_streaming_response_browse(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.connections.with_streaming_response.browse( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + connection = await response.parse() + assert_matches_type(ConnectionBrowseResponse, connection, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_browse(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.connections.with_raw_response.browse( + id="", + ) diff --git a/tests/api_resources/connectors/v1/test_installations.py b/tests/api_resources/connectors/v1/test_installations.py new file mode 100644 index 00000000..b97b2a38 --- /dev/null +++ b/tests/api_resources/connectors/v1/test_installations.py @@ -0,0 +1,156 @@ +# 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 casedev import Casedev, AsyncCasedev + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestInstallations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Casedev) -> None: + installation = client.connectors.v1.installations.list() + assert installation is None + + @parametrize + def test_method_list_with_all_params(self, client: Casedev) -> None: + installation = client.connectors.v1.installations.list( + application="application", + external_tenant_id="external_tenant_id", + ) + assert installation is None + + @parametrize + def test_raw_response_list(self, client: Casedev) -> None: + response = client.connectors.v1.installations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + installation = response.parse() + assert installation is None + + @parametrize + def test_streaming_response_list(self, client: Casedev) -> None: + with client.connectors.v1.installations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + installation = response.parse() + assert installation is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_ensure(self, client: Casedev) -> None: + installation = client.connectors.v1.installations.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) + assert installation is None + + @parametrize + def test_raw_response_ensure(self, client: Casedev) -> None: + response = client.connectors.v1.installations.with_raw_response.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + installation = response.parse() + assert installation is None + + @parametrize + def test_streaming_response_ensure(self, client: Casedev) -> None: + with client.connectors.v1.installations.with_streaming_response.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + installation = response.parse() + assert installation is None + + assert cast(Any, response.is_closed) is True + + +class TestAsyncInstallations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCasedev) -> None: + installation = await async_client.connectors.v1.installations.list() + assert installation is None + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: + installation = await async_client.connectors.v1.installations.list( + application="application", + external_tenant_id="external_tenant_id", + ) + assert installation is None + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.installations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + installation = await response.parse() + assert installation is None + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.installations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + installation = await response.parse() + assert installation is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_ensure(self, async_client: AsyncCasedev) -> None: + installation = await async_client.connectors.v1.installations.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) + assert installation is None + + @parametrize + async def test_raw_response_ensure(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.installations.with_raw_response.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + installation = await response.parse() + assert installation is None + + @parametrize + async def test_streaming_response_ensure(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.installations.with_streaming_response.ensure( + application="application", + external_tenant_id="external_tenant_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + installation = await response.parse() + assert installation is None + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/connectors/v1/test_links.py b/tests/api_resources/connectors/v1/test_links.py new file mode 100644 index 00000000..dd16ceef --- /dev/null +++ b/tests/api_resources/connectors/v1/test_links.py @@ -0,0 +1,454 @@ +# 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 casedev import Casedev, AsyncCasedev + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestLinks: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Casedev) -> None: + link = client.connectors.v1.links.retrieve( + "id", + ) + assert link is None + + @parametrize + def test_raw_response_retrieve(self, client: Casedev) -> None: + response = client.connectors.v1.links.with_raw_response.retrieve( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = response.parse() + assert link is None + + @parametrize + def test_streaming_response_retrieve(self, client: Casedev) -> None: + with client.connectors.v1.links.with_streaming_response.retrieve( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.links.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: Casedev) -> None: + link = client.connectors.v1.links.update( + id="id", + ) + assert link is None + + @parametrize + def test_method_update_with_all_params(self, client: Casedev) -> None: + link = client.connectors.v1.links.update( + id="id", + mode="once", + policy={}, + state="paused", + ) + assert link is None + + @parametrize + def test_raw_response_update(self, client: Casedev) -> None: + response = client.connectors.v1.links.with_raw_response.update( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = response.parse() + assert link is None + + @parametrize + def test_streaming_response_update(self, client: Casedev) -> None: + with client.connectors.v1.links.with_streaming_response.update( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.links.with_raw_response.update( + id="", + ) + + @parametrize + def test_method_list(self, client: Casedev) -> None: + link = client.connectors.v1.links.list() + assert link is None + + @parametrize + def test_method_list_with_all_params(self, client: Casedev) -> None: + link = client.connectors.v1.links.list( + connection_id="connection_id", + direction="import", + mode="once", + pair_id="pair_id", + state="ready", + vault_id="vault_id", + ) + assert link is None + + @parametrize + def test_raw_response_list(self, client: Casedev) -> None: + response = client.connectors.v1.links.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = response.parse() + assert link is None + + @parametrize + def test_streaming_response_list(self, client: Casedev) -> None: + with client.connectors.v1.links.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Casedev) -> None: + link = client.connectors.v1.links.delete( + id="id", + ) + assert link is None + + @parametrize + def test_method_delete_with_all_params(self, client: Casedev) -> None: + link = client.connectors.v1.links.delete( + id="id", + vault_docs="keep", + ) + assert link is None + + @parametrize + def test_raw_response_delete(self, client: Casedev) -> None: + response = client.connectors.v1.links.with_raw_response.delete( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = response.parse() + assert link is None + + @parametrize + def test_streaming_response_delete(self, client: Casedev) -> None: + with client.connectors.v1.links.with_streaming_response.delete( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.links.with_raw_response.delete( + id="", + ) + + @parametrize + def test_method_list_objects(self, client: Casedev) -> None: + link = client.connectors.v1.links.list_objects( + id="id", + ) + assert link is None + + @parametrize + def test_method_list_objects_with_all_params(self, client: Casedev) -> None: + link = client.connectors.v1.links.list_objects( + id="id", + cursor="cursor", + state="pending", + ) + assert link is None + + @parametrize + def test_raw_response_list_objects(self, client: Casedev) -> None: + response = client.connectors.v1.links.with_raw_response.list_objects( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = response.parse() + assert link is None + + @parametrize + def test_streaming_response_list_objects(self, client: Casedev) -> None: + with client.connectors.v1.links.with_streaming_response.list_objects( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_objects(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.connectors.v1.links.with_raw_response.list_objects( + id="", + ) + + +class TestAsyncLinks: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.retrieve( + "id", + ) + assert link is None + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.links.with_raw_response.retrieve( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = await response.parse() + assert link is None + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.links.with_streaming_response.retrieve( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = await response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.links.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_update(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.update( + id="id", + ) + assert link is None + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.update( + id="id", + mode="once", + policy={}, + state="paused", + ) + assert link is None + + @parametrize + async def test_raw_response_update(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.links.with_raw_response.update( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = await response.parse() + assert link is None + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.links.with_streaming_response.update( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = await response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.links.with_raw_response.update( + id="", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.list() + assert link is None + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.list( + connection_id="connection_id", + direction="import", + mode="once", + pair_id="pair_id", + state="ready", + vault_id="vault_id", + ) + assert link is None + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.links.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = await response.parse() + assert link is None + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.links.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = await response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.delete( + id="id", + ) + assert link is None + + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.delete( + id="id", + vault_docs="keep", + ) + assert link is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.links.with_raw_response.delete( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = await response.parse() + assert link is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.links.with_streaming_response.delete( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = await response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.links.with_raw_response.delete( + id="", + ) + + @parametrize + async def test_method_list_objects(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.list_objects( + id="id", + ) + assert link is None + + @parametrize + async def test_method_list_objects_with_all_params(self, async_client: AsyncCasedev) -> None: + link = await async_client.connectors.v1.links.list_objects( + id="id", + cursor="cursor", + state="pending", + ) + assert link is None + + @parametrize + async def test_raw_response_list_objects(self, async_client: AsyncCasedev) -> None: + response = await async_client.connectors.v1.links.with_raw_response.list_objects( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + link = await response.parse() + assert link is None + + @parametrize + async def test_streaming_response_list_objects(self, async_client: AsyncCasedev) -> None: + async with async_client.connectors.v1.links.with_streaming_response.list_objects( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + link = await response.parse() + assert link is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_objects(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.connectors.v1.links.with_raw_response.list_objects( + id="", + ) diff --git a/tests/api_resources/database/test_v1.py b/tests/api_resources/database/test_v1.py deleted file mode 100644 index 61b93aac..00000000 --- a/tests/api_resources/database/test_v1.py +++ /dev/null @@ -1,74 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.database import V1GetUsageResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestV1: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get_usage(self, client: Casedev) -> None: - v1 = client.database.v1.get_usage() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - @parametrize - def test_raw_response_get_usage(self, client: Casedev) -> None: - response = client.database.v1.with_raw_response.get_usage() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = response.parse() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - @parametrize - def test_streaming_response_get_usage(self, client: Casedev) -> None: - with client.database.v1.with_streaming_response.get_usage() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = response.parse() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncV1: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get_usage(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.database.v1.get_usage() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - @parametrize - async def test_raw_response_get_usage(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.with_raw_response.get_usage() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = await response.parse() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - @parametrize - async def test_streaming_response_get_usage(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.with_streaming_response.get_usage() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = await response.parse() - assert_matches_type(V1GetUsageResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/database/v1/test_projects.py b/tests/api_resources/database/v1/test_projects.py deleted file mode 100644 index 8a1d0ffe..00000000 --- a/tests/api_resources/database/v1/test_projects.py +++ /dev/null @@ -1,586 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.database.v1 import ( - ProjectListResponse, - ProjectCreateResponse, - ProjectDeleteResponse, - ProjectRetrieveResponse, - ProjectCreateBranchResponse, - ProjectListBranchesResponse, - ProjectGetConnectionResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestProjects: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - project = client.database.v1.projects.create( - name="litigation-docs-db", - ) - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - project = client.database.v1.projects.create( - name="litigation-docs-db", - description="Production database for litigation document management", - region="aws-us-east-1", - ) - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.create( - name="litigation-docs-db", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.create( - name="litigation-docs-db", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Casedev) -> None: - project = client.database.v1.projects.retrieve( - "id", - ) - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.database.v1.projects.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_list(self, client: Casedev) -> None: - project = client.database.v1.projects.list() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Casedev) -> None: - project = client.database.v1.projects.delete( - "id", - ) - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.delete( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.delete( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.database.v1.projects.with_raw_response.delete( - "", - ) - - @parametrize - def test_method_create_branch(self, client: Casedev) -> None: - project = client.database.v1.projects.create_branch( - id="id", - name="staging", - ) - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - def test_method_create_branch_with_all_params(self, client: Casedev) -> None: - project = client.database.v1.projects.create_branch( - id="id", - name="staging", - parent_branch_id="branch_main_123", - ) - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - def test_raw_response_create_branch(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.create_branch( - id="id", - name="staging", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_create_branch(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.create_branch( - id="id", - name="staging", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create_branch(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.database.v1.projects.with_raw_response.create_branch( - id="", - name="staging", - ) - - @parametrize - def test_method_get_connection(self, client: Casedev) -> None: - project = client.database.v1.projects.get_connection( - id="id", - ) - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - def test_method_get_connection_with_all_params(self, client: Casedev) -> None: - project = client.database.v1.projects.get_connection( - id="id", - branch="branch", - pooled=True, - ) - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - def test_raw_response_get_connection(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.get_connection( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_get_connection(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.get_connection( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_connection(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.database.v1.projects.with_raw_response.get_connection( - id="", - ) - - @parametrize - def test_method_list_branches(self, client: Casedev) -> None: - project = client.database.v1.projects.list_branches( - "id", - ) - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - @parametrize - def test_raw_response_list_branches(self, client: Casedev) -> None: - response = client.database.v1.projects.with_raw_response.list_branches( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = response.parse() - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - @parametrize - def test_streaming_response_list_branches(self, client: Casedev) -> None: - with client.database.v1.projects.with_streaming_response.list_branches( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = response.parse() - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_branches(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.database.v1.projects.with_raw_response.list_branches( - "", - ) - - -class TestAsyncProjects: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.create( - name="litigation-docs-db", - ) - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.create( - name="litigation-docs-db", - description="Production database for litigation document management", - region="aws-us-east-1", - ) - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.create( - name="litigation-docs-db", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.create( - name="litigation-docs-db", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectCreateResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.retrieve( - "id", - ) - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectRetrieveResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.database.v1.projects.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.list() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectListResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.delete( - "id", - ) - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.delete( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.delete( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectDeleteResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.database.v1.projects.with_raw_response.delete( - "", - ) - - @parametrize - async def test_method_create_branch(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.create_branch( - id="id", - name="staging", - ) - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - async def test_method_create_branch_with_all_params(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.create_branch( - id="id", - name="staging", - parent_branch_id="branch_main_123", - ) - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_create_branch(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.create_branch( - id="id", - name="staging", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_create_branch(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.create_branch( - id="id", - name="staging", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectCreateBranchResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create_branch(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.database.v1.projects.with_raw_response.create_branch( - id="", - name="staging", - ) - - @parametrize - async def test_method_get_connection(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.get_connection( - id="id", - ) - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - async def test_method_get_connection_with_all_params(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.get_connection( - id="id", - branch="branch", - pooled=True, - ) - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_get_connection(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.get_connection( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_get_connection(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.get_connection( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectGetConnectionResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_connection(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.database.v1.projects.with_raw_response.get_connection( - id="", - ) - - @parametrize - async def test_method_list_branches(self, async_client: AsyncCasedev) -> None: - project = await async_client.database.v1.projects.list_branches( - "id", - ) - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - @parametrize - async def test_raw_response_list_branches(self, async_client: AsyncCasedev) -> None: - response = await async_client.database.v1.projects.with_raw_response.list_branches( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - project = await response.parse() - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - @parametrize - async def test_streaming_response_list_branches(self, async_client: AsyncCasedev) -> None: - async with async_client.database.v1.projects.with_streaming_response.list_branches( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - project = await response.parse() - assert_matches_type(ProjectListBranchesResponse, project, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_branches(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.database.v1.projects.with_raw_response.list_branches( - "", - ) diff --git a/tests/api_resources/format/test_v1.py b/tests/api_resources/format/test_v1.py deleted file mode 100644 index 67a1690a..00000000 --- a/tests/api_resources/format/test_v1.py +++ /dev/null @@ -1,170 +0,0 @@ -# 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 httpx -import pytest -from respx import MockRouter - -from casedev import Casedev, AsyncCasedev -from casedev._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestV1: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_create_document(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.format.v1.create_document( - content="content", - output_format="pdf", - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_create_document_with_all_params(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.format.v1.create_document( - content="content", - output_format="pdf", - input_format="md", - options={ - "components": [ - { - "content": "content", - "styles": {}, - "template_id": "templateId", - "variables": {}, - } - ] - }, - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_raw_response_create_document(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = client.format.v1.with_raw_response.create_document( - content="content", - output_format="pdf", - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert v1.json() == {"foo": "bar"} - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_streaming_response_create_document(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - with client.format.v1.with_streaming_response.create_document( - content="content", - output_format="pdf", - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, StreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True - - -class TestAsyncV1: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_create_document(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.format.v1.create_document( - content="content", - output_format="pdf", - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_create_document_with_all_params( - self, async_client: AsyncCasedev, respx_mock: MockRouter - ) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.format.v1.create_document( - content="content", - output_format="pdf", - input_format="md", - options={ - "components": [ - { - "content": "content", - "styles": {}, - "template_id": "templateId", - "variables": {}, - } - ] - }, - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_raw_response_create_document(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = await async_client.format.v1.with_raw_response.create_document( - content="content", - output_format="pdf", - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert await v1.json() == {"foo": "bar"} - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_streaming_response_create_document(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/format/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - async with async_client.format.v1.with_streaming_response.create_document( - content="content", - output_format="pdf", - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncStreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True diff --git a/tests/api_resources/format/v1/__init__.py b/tests/api_resources/format/v1/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/format/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/format/v1/test_templates.py b/tests/api_resources/format/v1/test_templates.py deleted file mode 100644 index 5817c69b..00000000 --- a/tests/api_resources/format/v1/test_templates.py +++ /dev/null @@ -1,268 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.format.v1 import ( - TemplateListResponse, - TemplateCreateResponse, - TemplateRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTemplates: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - template = client.format.v1.templates.create( - content="content", - name="name", - type="caption", - ) - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - template = client.format.v1.templates.create( - content="content", - name="name", - type="caption", - description="description", - styles={}, - tags=["string"], - variables=["string"], - ) - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.format.v1.templates.with_raw_response.create( - content="content", - name="name", - type="caption", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = response.parse() - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.format.v1.templates.with_streaming_response.create( - content="content", - name="name", - type="caption", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = response.parse() - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Casedev) -> None: - template = client.format.v1.templates.retrieve( - "id", - ) - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Casedev) -> None: - response = client.format.v1.templates.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = response.parse() - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Casedev) -> None: - with client.format.v1.templates.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = response.parse() - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.format.v1.templates.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_list(self, client: Casedev) -> None: - template = client.format.v1.templates.list() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Casedev) -> None: - template = client.format.v1.templates.list( - type="type", - ) - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Casedev) -> None: - response = client.format.v1.templates.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = response.parse() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Casedev) -> None: - with client.format.v1.templates.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = response.parse() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncTemplates: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - template = await async_client.format.v1.templates.create( - content="content", - name="name", - type="caption", - ) - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - template = await async_client.format.v1.templates.create( - content="content", - name="name", - type="caption", - description="description", - styles={}, - tags=["string"], - variables=["string"], - ) - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.format.v1.templates.with_raw_response.create( - content="content", - name="name", - type="caption", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = await response.parse() - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.format.v1.templates.with_streaming_response.create( - content="content", - name="name", - type="caption", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = await response.parse() - assert_matches_type(TemplateCreateResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: - template = await async_client.format.v1.templates.retrieve( - "id", - ) - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: - response = await async_client.format.v1.templates.with_raw_response.retrieve( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = await response.parse() - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: - async with async_client.format.v1.templates.with_streaming_response.retrieve( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = await response.parse() - assert_matches_type(TemplateRetrieveResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.format.v1.templates.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncCasedev) -> None: - template = await async_client.format.v1.templates.list() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: - template = await async_client.format.v1.templates.list( - type="type", - ) - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: - response = await async_client.format.v1.templates.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - template = await response.parse() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: - async with async_client.format.v1.templates.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - template = await response.parse() - assert_matches_type(TemplateListResponse, template, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/legal/test_v1.py b/tests/api_resources/legal/test_v1.py index c1edc410..e4e24632 100644 --- a/tests/api_resources/legal/test_v1.py +++ b/tests/api_resources/legal/test_v1.py @@ -12,7 +12,6 @@ from casedev._utils import parse_date from casedev.types.legal import ( V1FindResponse, - V1DraftResponse, V1DocketResponse, V1VerifyResponse, V1SimilarResponse, @@ -81,59 +80,6 @@ def test_streaming_response_docket(self, client: Casedev) -> None: assert cast(Any, response.is_closed) is True - @parametrize - def test_method_draft(self, client: Casedev) -> None: - v1 = client.legal.v1.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - def test_method_draft_with_all_params(self, client: Casedev) -> None: - v1 = client.legal.v1.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - citations=True, - format="format", - length={ - "target": 0, - "unit": "words", - }, - model="model", - object_ids=["string"], - output_name="output_name", - output_type="pdf", - verified=True, - ) - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - def test_raw_response_draft(self, client: Casedev) -> None: - response = client.legal.v1.with_raw_response.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = response.parse() - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - def test_streaming_response_draft(self, client: Casedev) -> None: - with client.legal.v1.with_streaming_response.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = response.parse() - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize def test_method_find(self, client: Casedev) -> None: v1 = client.legal.v1.find( @@ -641,59 +587,6 @@ async def test_streaming_response_docket(self, async_client: AsyncCasedev) -> No assert cast(Any, response.is_closed) is True - @parametrize - async def test_method_draft(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.legal.v1.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - async def test_method_draft_with_all_params(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.legal.v1.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - citations=True, - format="format", - length={ - "target": 0, - "unit": "words", - }, - model="model", - object_ids=["string"], - output_name="output_name", - output_type="pdf", - verified=True, - ) - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - async def test_raw_response_draft(self, async_client: AsyncCasedev) -> None: - response = await async_client.legal.v1.with_raw_response.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = await response.parse() - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - @parametrize - async def test_streaming_response_draft(self, async_client: AsyncCasedev) -> None: - async with async_client.legal.v1.with_streaming_response.draft( - instructions="xxxxxxxxxx", - vault_id="vault_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = await response.parse() - assert_matches_type(V1DraftResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize async def test_method_find(self, async_client: AsyncCasedev) -> None: v1 = await async_client.legal.v1.find( diff --git a/tests/api_resources/database/v1/__init__.py b/tests/api_resources/linc/__init__.py similarity index 100% rename from tests/api_resources/database/v1/__init__.py rename to tests/api_resources/linc/__init__.py diff --git a/tests/api_resources/format/__init__.py b/tests/api_resources/linc/v1/__init__.py similarity index 100% rename from tests/api_resources/format/__init__.py rename to tests/api_resources/linc/v1/__init__.py diff --git a/tests/api_resources/linc/v1/test_sessions.py b/tests/api_resources/linc/v1/test_sessions.py new file mode 100644 index 00000000..be6e84c0 --- /dev/null +++ b/tests/api_resources/linc/v1/test_sessions.py @@ -0,0 +1,776 @@ +# 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 casedev import Casedev, AsyncCasedev + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Casedev) -> None: + session = client.linc.v1.sessions.create() + assert session is None + + @parametrize + def test_method_create_with_all_params(self, client: Casedev) -> None: + session = client.linc.v1.sessions.create( + document_template_slugs=["string"], + idle_timeout_ms=0, + include_document_templates=True, + instructions="instructions", + model="model", + scoped_api_key="scopedApiKey", + service_tier="default", + skill_slugs=["string"], + title="title", + vault_ids=["string"], + ) + assert session is None + + @parametrize + def test_raw_response_create(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_create(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: Casedev) -> None: + session = client.linc.v1.sessions.delete( + "id", + ) + assert session is None + + @parametrize + def test_raw_response_delete(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.delete( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_delete(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.delete( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.delete( + "", + ) + + @parametrize + def test_method_cancel(self, client: Casedev) -> None: + session = client.linc.v1.sessions.cancel( + id="id", + ) + assert session is None + + @parametrize + def test_method_cancel_with_all_params(self, client: Casedev) -> None: + session = client.linc.v1.sessions.cancel( + id="id", + clear_queue=True, + ) + assert session is None + + @parametrize + def test_raw_response_cancel(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.cancel( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_cancel(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.cancel( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_cancel(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.cancel( + id="", + ) + + @parametrize + def test_method_ingest_events(self, client: Casedev) -> None: + session = client.linc.v1.sessions.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + assert session is None + + @parametrize + def test_raw_response_ingest_events(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_ingest_events(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_ingest_events(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.ingest_events( + id="", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + + @parametrize + def test_method_retrieve_events(self, client: Casedev) -> None: + session = client.linc.v1.sessions.retrieve_events( + id="id", + ) + assert session is None + + @parametrize + def test_method_retrieve_events_with_all_params(self, client: Casedev) -> None: + session = client.linc.v1.sessions.retrieve_events( + id="id", + after_seq=0, + cursor=0, + exclude_event_types=["string"], + limit=1, + ) + assert session is None + + @parametrize + def test_raw_response_retrieve_events(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.retrieve_events( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_retrieve_events(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.retrieve_events( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve_events(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.retrieve_events( + id="", + ) + + @parametrize + def test_method_retrieve_messages(self, client: Casedev) -> None: + session = client.linc.v1.sessions.retrieve_messages( + id="id", + ) + assert session is None + + @parametrize + def test_method_retrieve_messages_with_all_params(self, client: Casedev) -> None: + session = client.linc.v1.sessions.retrieve_messages( + id="id", + after_seq=0, + cursor=0, + limit=1, + ) + assert session is None + + @parametrize + def test_raw_response_retrieve_messages(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.retrieve_messages( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_retrieve_messages(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.retrieve_messages( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve_messages(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.retrieve_messages( + id="", + ) + + @parametrize + def test_method_retrieve_state(self, client: Casedev) -> None: + session = client.linc.v1.sessions.retrieve_state( + "id", + ) + assert session is None + + @parametrize + def test_raw_response_retrieve_state(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.retrieve_state( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_retrieve_state(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.retrieve_state( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve_state(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.linc.v1.sessions.with_raw_response.retrieve_state( + "", + ) + + @parametrize + def test_method_send_rpc(self, client: Casedev) -> None: + session = client.linc.v1.sessions.send_rpc( + path_id="id", + type="type", + ) + assert session is None + + @parametrize + def test_method_send_rpc_with_all_params(self, client: Casedev) -> None: + session = client.linc.v1.sessions.send_rpc( + path_id="id", + type="type", + body_id="id", + ) + assert session is None + + @parametrize + def test_raw_response_send_rpc(self, client: Casedev) -> None: + response = client.linc.v1.sessions.with_raw_response.send_rpc( + path_id="id", + type="type", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = response.parse() + assert session is None + + @parametrize + def test_streaming_response_send_rpc(self, client: Casedev) -> None: + with client.linc.v1.sessions.with_streaming_response.send_rpc( + path_id="id", + type="type", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_send_rpc(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + client.linc.v1.sessions.with_raw_response.send_rpc( + path_id="", + type="type", + ) + + +class TestAsyncSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.create() + assert session is None + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.create( + document_template_slugs=["string"], + idle_timeout_ms=0, + include_document_templates=True, + instructions="instructions", + model="model", + scoped_api_key="scopedApiKey", + service_tier="default", + skill_slugs=["string"], + title="title", + vault_ids=["string"], + ) + assert session is None + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.delete( + "id", + ) + assert session is None + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.delete( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.delete( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.delete( + "", + ) + + @parametrize + async def test_method_cancel(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.cancel( + id="id", + ) + assert session is None + + @parametrize + async def test_method_cancel_with_all_params(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.cancel( + id="id", + clear_queue=True, + ) + assert session is None + + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.cancel( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.cancel( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_cancel(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.cancel( + id="", + ) + + @parametrize + async def test_method_ingest_events(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + assert session is None + + @parametrize + async def test_raw_response_ingest_events(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_ingest_events(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.ingest_events( + id="id", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_ingest_events(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.ingest_events( + id="", + frames=[ + { + "event": {"foo": "bar"}, + "seq": 1, + "type": "type", + } + ], + ) + + @parametrize + async def test_method_retrieve_events(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.retrieve_events( + id="id", + ) + assert session is None + + @parametrize + async def test_method_retrieve_events_with_all_params(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.retrieve_events( + id="id", + after_seq=0, + cursor=0, + exclude_event_types=["string"], + limit=1, + ) + assert session is None + + @parametrize + async def test_raw_response_retrieve_events(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.retrieve_events( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_retrieve_events(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.retrieve_events( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve_events(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.retrieve_events( + id="", + ) + + @parametrize + async def test_method_retrieve_messages(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.retrieve_messages( + id="id", + ) + assert session is None + + @parametrize + async def test_method_retrieve_messages_with_all_params(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.retrieve_messages( + id="id", + after_seq=0, + cursor=0, + limit=1, + ) + assert session is None + + @parametrize + async def test_raw_response_retrieve_messages(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.retrieve_messages( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_retrieve_messages(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.retrieve_messages( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve_messages(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.retrieve_messages( + id="", + ) + + @parametrize + async def test_method_retrieve_state(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.retrieve_state( + "id", + ) + assert session is None + + @parametrize + async def test_raw_response_retrieve_state(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.retrieve_state( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_retrieve_state(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.retrieve_state( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve_state(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.retrieve_state( + "", + ) + + @parametrize + async def test_method_send_rpc(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.send_rpc( + path_id="id", + type="type", + ) + assert session is None + + @parametrize + async def test_method_send_rpc_with_all_params(self, async_client: AsyncCasedev) -> None: + session = await async_client.linc.v1.sessions.send_rpc( + path_id="id", + type="type", + body_id="id", + ) + assert session is None + + @parametrize + async def test_raw_response_send_rpc(self, async_client: AsyncCasedev) -> None: + response = await async_client.linc.v1.sessions.with_raw_response.send_rpc( + path_id="id", + type="type", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + session = await response.parse() + assert session is None + + @parametrize + async def test_streaming_response_send_rpc(self, async_client: AsyncCasedev) -> None: + async with async_client.linc.v1.sessions.with_streaming_response.send_rpc( + path_id="id", + type="type", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + session = await response.parse() + assert session is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_send_rpc(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_id` but received ''"): + await async_client.linc.v1.sessions.with_raw_response.send_rpc( + path_id="", + type="type", + ) diff --git a/tests/api_resources/mail/__init__.py b/tests/api_resources/mail/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/mail/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/mail/v1/__init__.py b/tests/api_resources/mail/v1/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/mail/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/mail/v1/test_inboxes.py b/tests/api_resources/mail/v1/test_inboxes.py deleted file mode 100644 index 02cb0b7d..00000000 --- a/tests/api_resources/mail/v1/test_inboxes.py +++ /dev/null @@ -1,930 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestInboxes: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.create() - assert inbox is None - - @parametrize - def test_method_create_with_all_params(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.create( - address="address", - display_name="displayName", - ) - assert inbox is None - - @parametrize - def test_raw_response_create(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_create(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.retrieve( - "inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_retrieve(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.retrieve( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_retrieve(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.retrieve( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_list(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.list() - assert inbox is None - - @parametrize - def test_raw_response_list(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_list(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.delete( - "inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_delete(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.delete( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_delete(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.delete( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.delete( - "", - ) - - @parametrize - def test_method_get_attachment(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) - assert inbox is None - - @parametrize - def test_raw_response_get_attachment(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_get_attachment(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_attachment(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="", - message_id="messageId", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `attachment_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="", - inbox_id="inboxId", - message_id="messageId", - ) - - @parametrize - def test_method_get_message(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.get_message( - message_id="messageId", - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_get_message(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.get_message( - message_id="messageId", - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_get_message(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.get_message( - message_id="messageId", - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_message(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_message( - message_id="messageId", - inbox_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_message( - message_id="", - inbox_id="inboxId", - ) - - @parametrize - def test_method_get_policy(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.get_policy( - "inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_get_policy(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.get_policy( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_get_policy(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.get_policy( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_policy(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.get_policy( - "", - ) - - @parametrize - def test_method_list_messages(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.list_messages( - "inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_list_messages(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.list_messages( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_list_messages(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.list_messages( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_messages(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.list_messages( - "", - ) - - @parametrize - def test_method_reply(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.reply( - message_id="messageId", - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_reply(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.reply( - message_id="messageId", - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_reply(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.reply( - message_id="messageId", - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_reply(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.reply( - message_id="messageId", - inbox_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.reply( - message_id="", - inbox_id="inboxId", - ) - - @parametrize - def test_method_send(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.send( - "inboxId", - ) - assert inbox is None - - @parametrize - def test_raw_response_send(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.send( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_send(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.send( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_send(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.send( - "", - ) - - @parametrize - def test_method_set_policy(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.set_policy( - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - def test_method_set_policy_with_all_params(self, client: Casedev) -> None: - inbox = client.mail.v1.inboxes.set_policy( - inbox_id="inboxId", - allowed_sender_patterns=["string"], - enforce_sender_allowlist=True, - read_access_rules=["string"], - reply_access_rules=["string"], - send_access_rules=["string"], - ) - assert inbox is None - - @parametrize - def test_raw_response_set_policy(self, client: Casedev) -> None: - response = client.mail.v1.inboxes.with_raw_response.set_policy( - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = response.parse() - assert inbox is None - - @parametrize - def test_streaming_response_set_policy(self, client: Casedev) -> None: - with client.mail.v1.inboxes.with_streaming_response.set_policy( - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_set_policy(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - client.mail.v1.inboxes.with_raw_response.set_policy( - inbox_id="", - ) - - -class TestAsyncInboxes: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.create() - assert inbox is None - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.create( - address="address", - display_name="displayName", - ) - assert inbox is None - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.retrieve( - "inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.retrieve( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.retrieve( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.list() - assert inbox is None - - @parametrize - async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.delete( - "inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.delete( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.delete( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.delete( - "", - ) - - @parametrize - async def test_method_get_attachment(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_get_attachment(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_get_attachment(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="messageId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_attachment(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="", - message_id="messageId", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="attachmentId", - inbox_id="inboxId", - message_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `attachment_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_attachment( - attachment_id="", - inbox_id="inboxId", - message_id="messageId", - ) - - @parametrize - async def test_method_get_message(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.get_message( - message_id="messageId", - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_get_message(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.get_message( - message_id="messageId", - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_get_message(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.get_message( - message_id="messageId", - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_message(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_message( - message_id="messageId", - inbox_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_message( - message_id="", - inbox_id="inboxId", - ) - - @parametrize - async def test_method_get_policy(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.get_policy( - "inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_get_policy(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.get_policy( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_get_policy(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.get_policy( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_policy(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.get_policy( - "", - ) - - @parametrize - async def test_method_list_messages(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.list_messages( - "inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_list_messages(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.list_messages( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_list_messages(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.list_messages( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_messages(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.list_messages( - "", - ) - - @parametrize - async def test_method_reply(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.reply( - message_id="messageId", - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_reply(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.reply( - message_id="messageId", - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_reply(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.reply( - message_id="messageId", - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_reply(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.reply( - message_id="messageId", - inbox_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.reply( - message_id="", - inbox_id="inboxId", - ) - - @parametrize - async def test_method_send(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.send( - "inboxId", - ) - assert inbox is None - - @parametrize - async def test_raw_response_send(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.send( - "inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_send(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.send( - "inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_send(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.send( - "", - ) - - @parametrize - async def test_method_set_policy(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.set_policy( - inbox_id="inboxId", - ) - assert inbox is None - - @parametrize - async def test_method_set_policy_with_all_params(self, async_client: AsyncCasedev) -> None: - inbox = await async_client.mail.v1.inboxes.set_policy( - inbox_id="inboxId", - allowed_sender_patterns=["string"], - enforce_sender_allowlist=True, - read_access_rules=["string"], - reply_access_rules=["string"], - send_access_rules=["string"], - ) - assert inbox is None - - @parametrize - async def test_raw_response_set_policy(self, async_client: AsyncCasedev) -> None: - response = await async_client.mail.v1.inboxes.with_raw_response.set_policy( - inbox_id="inboxId", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - inbox = await response.parse() - assert inbox is None - - @parametrize - async def test_streaming_response_set_policy(self, async_client: AsyncCasedev) -> None: - async with async_client.mail.v1.inboxes.with_streaming_response.set_policy( - inbox_id="inboxId", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - inbox = await response.parse() - assert inbox is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_set_policy(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `inbox_id` but received ''"): - await async_client.mail.v1.inboxes.with_raw_response.set_policy( - inbox_id="", - ) diff --git a/tests/api_resources/matters/v1/test_work_items.py b/tests/api_resources/matters/v1/test_work_items.py index 8456b862..7128c0af 100644 --- a/tests/api_resources/matters/v1/test_work_items.py +++ b/tests/api_resources/matters/v1/test_work_items.py @@ -252,7 +252,6 @@ def test_method_decide_with_all_params(self, client: Casedev) -> None: work_item_id="workItemId", id="id", decision="approve", - agent_type_id="agent_type_id", metadata={"foo": "bar"}, reason="reason", ) @@ -302,54 +301,6 @@ def test_path_params_decide(self, client: Casedev) -> None: decision="approve", ) - @parametrize - def test_method_list_executions(self, client: Casedev) -> None: - work_item = client.matters.v1.work_items.list_executions( - work_item_id="workItemId", - id="id", - ) - assert work_item is None - - @parametrize - def test_raw_response_list_executions(self, client: Casedev) -> None: - response = client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="workItemId", - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - work_item = response.parse() - assert work_item is None - - @parametrize - def test_streaming_response_list_executions(self, client: Casedev) -> None: - with client.matters.v1.work_items.with_streaming_response.list_executions( - work_item_id="workItemId", - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - work_item = response.parse() - assert work_item is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_executions(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="workItemId", - id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `work_item_id` but received ''"): - client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="", - id="id", - ) - class TestAsyncWorkItems: parametrize = pytest.mark.parametrize( @@ -592,7 +543,6 @@ async def test_method_decide_with_all_params(self, async_client: AsyncCasedev) - work_item_id="workItemId", id="id", decision="approve", - agent_type_id="agent_type_id", metadata={"foo": "bar"}, reason="reason", ) @@ -641,51 +591,3 @@ async def test_path_params_decide(self, async_client: AsyncCasedev) -> None: id="id", decision="approve", ) - - @parametrize - async def test_method_list_executions(self, async_client: AsyncCasedev) -> None: - work_item = await async_client.matters.v1.work_items.list_executions( - work_item_id="workItemId", - id="id", - ) - assert work_item is None - - @parametrize - async def test_raw_response_list_executions(self, async_client: AsyncCasedev) -> None: - response = await async_client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="workItemId", - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - work_item = await response.parse() - assert work_item is None - - @parametrize - async def test_streaming_response_list_executions(self, async_client: AsyncCasedev) -> None: - async with async_client.matters.v1.work_items.with_streaming_response.list_executions( - work_item_id="workItemId", - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - work_item = await response.parse() - assert work_item is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_executions(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="workItemId", - id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `work_item_id` but received ''"): - await async_client.matters.v1.work_items.with_raw_response.list_executions( - work_item_id="", - id="id", - ) diff --git a/tests/api_resources/media/v1/transcripts/test_retrieve.py b/tests/api_resources/media/v1/transcripts/test_retrieve.py new file mode 100644 index 00000000..aba332cc --- /dev/null +++ b/tests/api_resources/media/v1/transcripts/test_retrieve.py @@ -0,0 +1,116 @@ +# 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 casedev import Casedev, AsyncCasedev +from tests.utils import assert_matches_type +from casedev.types.media.v1.transcripts import RetrieveCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRetrieve: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Casedev) -> None: + retrieve = client.media.v1.transcripts.retrieve.create( + object_id="object_id", + vault_id="vault_id", + ) + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Casedev) -> None: + retrieve = client.media.v1.transcripts.retrieve.create( + object_id="object_id", + vault_id="vault_id", + transcript={ + "object_id": "object_id", + "vault_id": "vault_id", + }, + ) + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Casedev) -> None: + response = client.media.v1.transcripts.retrieve.with_raw_response.create( + object_id="object_id", + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + retrieve = response.parse() + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Casedev) -> None: + with client.media.v1.transcripts.retrieve.with_streaming_response.create( + object_id="object_id", + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + retrieve = response.parse() + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRetrieve: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncCasedev) -> None: + retrieve = await async_client.media.v1.transcripts.retrieve.create( + object_id="object_id", + vault_id="vault_id", + ) + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCasedev) -> None: + retrieve = await async_client.media.v1.transcripts.retrieve.create( + object_id="object_id", + vault_id="vault_id", + transcript={ + "object_id": "object_id", + "vault_id": "vault_id", + }, + ) + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCasedev) -> None: + response = await async_client.media.v1.transcripts.retrieve.with_raw_response.create( + object_id="object_id", + vault_id="vault_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + retrieve = await response.parse() + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCasedev) -> None: + async with async_client.media.v1.transcripts.retrieve.with_streaming_response.create( + object_id="object_id", + vault_id="vault_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + retrieve = await response.parse() + assert_matches_type(RetrieveCreateResponse, retrieve, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/search/test_v1.py b/tests/api_resources/search/test_v1.py index c33c4361..fa704f35 100644 --- a/tests/api_resources/search/test_v1.py +++ b/tests/api_resources/search/test_v1.py @@ -15,8 +15,6 @@ V1SearchResponse, V1SimilarResponse, V1ContentsResponse, - V1ResearchResponse, - V1RetrieveResearchResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -120,94 +118,6 @@ def test_streaming_response_contents(self, client: Casedev) -> None: assert cast(Any, response.is_closed) is True - @parametrize - def test_method_research(self, client: Casedev) -> None: - v1 = client.search.v1.research( - instructions="instructions", - ) - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - def test_method_research_with_all_params(self, client: Casedev) -> None: - v1 = client.search.v1.research( - instructions="instructions", - model="fast", - output_schema={}, - query="query", - ) - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - def test_raw_response_research(self, client: Casedev) -> None: - response = client.search.v1.with_raw_response.research( - instructions="instructions", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = response.parse() - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - def test_streaming_response_research(self, client: Casedev) -> None: - with client.search.v1.with_streaming_response.research( - instructions="instructions", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = response.parse() - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve_research(self, client: Casedev) -> None: - v1 = client.search.v1.retrieve_research( - id="id", - ) - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - def test_method_retrieve_research_with_all_params(self, client: Casedev) -> None: - v1 = client.search.v1.retrieve_research( - id="id", - events="events", - stream=True, - ) - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - def test_raw_response_retrieve_research(self, client: Casedev) -> None: - response = client.search.v1.with_raw_response.retrieve_research( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = response.parse() - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - def test_streaming_response_retrieve_research(self, client: Casedev) -> None: - with client.search.v1.with_streaming_response.retrieve_research( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = response.parse() - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve_research(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.search.v1.with_raw_response.retrieve_research( - id="", - ) - @parametrize def test_method_search(self, client: Casedev) -> None: v1 = client.search.v1.search( @@ -407,94 +317,6 @@ async def test_streaming_response_contents(self, async_client: AsyncCasedev) -> assert cast(Any, response.is_closed) is True - @parametrize - async def test_method_research(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.search.v1.research( - instructions="instructions", - ) - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - async def test_method_research_with_all_params(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.search.v1.research( - instructions="instructions", - model="fast", - output_schema={}, - query="query", - ) - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - async def test_raw_response_research(self, async_client: AsyncCasedev) -> None: - response = await async_client.search.v1.with_raw_response.research( - instructions="instructions", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = await response.parse() - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - @parametrize - async def test_streaming_response_research(self, async_client: AsyncCasedev) -> None: - async with async_client.search.v1.with_streaming_response.research( - instructions="instructions", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = await response.parse() - assert_matches_type(V1ResearchResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve_research(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.search.v1.retrieve_research( - id="id", - ) - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - async def test_method_retrieve_research_with_all_params(self, async_client: AsyncCasedev) -> None: - v1 = await async_client.search.v1.retrieve_research( - id="id", - events="events", - stream=True, - ) - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_research(self, async_client: AsyncCasedev) -> None: - response = await async_client.search.v1.with_raw_response.retrieve_research( - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - v1 = await response.parse() - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_research(self, async_client: AsyncCasedev) -> None: - async with async_client.search.v1.with_streaming_response.retrieve_research( - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - v1 = await response.parse() - assert_matches_type(V1RetrieveResearchResponse, v1, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve_research(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.search.v1.with_raw_response.retrieve_research( - id="", - ) - @parametrize async def test_method_search(self, async_client: AsyncCasedev) -> None: v1 = await async_client.search.v1.search( diff --git a/tests/api_resources/superdoc/__init__.py b/tests/api_resources/superdoc/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/superdoc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/superdoc/test_v1.py b/tests/api_resources/superdoc/test_v1.py deleted file mode 100644 index 458417cb..00000000 --- a/tests/api_resources/superdoc/test_v1.py +++ /dev/null @@ -1,320 +0,0 @@ -# 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 httpx -import pytest -from respx import MockRouter - -from casedev import Casedev, AsyncCasedev -from casedev._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestV1: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_annotate(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.superdoc.v1.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_annotate_with_all_params(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.superdoc.v1.annotate( - document={ - "base64": "base64", - "url": "url", - }, - fields=[ - { - "type": "text", - "value": "string", - "id": "id", - "group": "group", - "options": { - "height": 0, - "width": 0, - }, - } - ], - output_format="docx", - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_raw_response_annotate(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = client.superdoc.v1.with_raw_response.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert v1.json() == {"foo": "bar"} - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_streaming_response_annotate(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - with client.superdoc.v1.with_streaming_response.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, StreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_convert(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.superdoc.v1.convert( - from_="docx", - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_convert_with_all_params(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = client.superdoc.v1.convert( - from_="docx", - document_base64="document_base64", - document_url="document_url", - to="pdf", - ) - assert v1.is_closed - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_raw_response_convert(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = client.superdoc.v1.with_raw_response.convert( - from_="docx", - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert v1.json() == {"foo": "bar"} - assert isinstance(v1, BinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_streaming_response_convert(self, client: Casedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - with client.superdoc.v1.with_streaming_response.convert( - from_="docx", - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, StreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True - - -class TestAsyncV1: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_annotate(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.superdoc.v1.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_annotate_with_all_params(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.superdoc.v1.annotate( - document={ - "base64": "base64", - "url": "url", - }, - fields=[ - { - "type": "text", - "value": "string", - "id": "id", - "group": "group", - "options": { - "height": 0, - "width": 0, - }, - } - ], - output_format="docx", - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_raw_response_annotate(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = await async_client.superdoc.v1.with_raw_response.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert await v1.json() == {"foo": "bar"} - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_streaming_response_annotate(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/annotate").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - async with async_client.superdoc.v1.with_streaming_response.annotate( - document={}, - fields=[ - { - "type": "text", - "value": "string", - } - ], - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncStreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_convert(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.superdoc.v1.convert( - from_="docx", - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_convert_with_all_params(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - v1 = await async_client.superdoc.v1.convert( - from_="docx", - document_base64="document_base64", - document_url="document_url", - to="pdf", - ) - assert v1.is_closed - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_raw_response_convert(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - v1 = await async_client.superdoc.v1.with_raw_response.convert( - from_="docx", - ) - - assert v1.is_closed is True - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - assert await v1.json() == {"foo": "bar"} - assert isinstance(v1, AsyncBinaryAPIResponse) - - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_streaming_response_convert(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: - respx_mock.post("/superdoc/v1/convert").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - async with async_client.superdoc.v1.with_streaming_response.convert( - from_="docx", - ) as v1: - assert not v1.is_closed - assert v1.http_request.headers.get("X-Stainless-Lang") == "python" - - assert await v1.json() == {"foo": "bar"} - assert cast(Any, v1.is_closed) is True - assert isinstance(v1, AsyncStreamedBinaryAPIResponse) - - assert cast(Any, v1.is_closed) is True diff --git a/tests/api_resources/test_vault.py b/tests/api_resources/test_vault.py index dbf210d8..704c42b5 100644 --- a/tests/api_resources/test_vault.py +++ b/tests/api_resources/test_vault.py @@ -233,32 +233,33 @@ def test_path_params_delete(self, client: Casedev) -> None: ) @parametrize - def test_method_confirm_upload_overload_1(self, client: Casedev) -> None: + def test_method_confirm_upload(self, client: Casedev) -> None: vault = client.vault.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - def test_method_confirm_upload_with_all_params_overload_1(self, client: Casedev) -> None: + def test_method_confirm_upload_with_all_params(self, client: Casedev) -> None: vault = client.vault.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, + auto_ingest=True, + error_code="errorCode", + error_message="errorMessage", etag="etag", + size_bytes=1, ) assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - def test_raw_response_confirm_upload_overload_1(self, client: Casedev) -> None: + def test_raw_response_confirm_upload(self, client: Casedev) -> None: response = client.vault.with_raw_response.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) @@ -268,11 +269,10 @@ def test_raw_response_confirm_upload_overload_1(self, client: Casedev) -> None: assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - def test_streaming_response_confirm_upload_overload_1(self, client: Casedev) -> None: + def test_streaming_response_confirm_upload(self, client: Casedev) -> None: with client.vault.with_streaming_response.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) as response: assert not response.is_closed @@ -284,12 +284,11 @@ def test_streaming_response_confirm_upload_overload_1(self, client: Casedev) -> assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_confirm_upload_overload_1(self, client: Casedev) -> None: + def test_path_params_confirm_upload(self, client: Casedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): client.vault.with_raw_response.confirm_upload( object_id="objectId", id="", - size_bytes=1, success=True, ) @@ -297,73 +296,9 @@ def test_path_params_confirm_upload_overload_1(self, client: Casedev) -> None: client.vault.with_raw_response.confirm_upload( object_id="", id="id", - size_bytes=1, success=True, ) - @parametrize - def test_method_confirm_upload_overload_2(self, client: Casedev) -> None: - vault = client.vault.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - @parametrize - def test_raw_response_confirm_upload_overload_2(self, client: Casedev) -> None: - response = client.vault.with_raw_response.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - vault = response.parse() - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - @parametrize - def test_streaming_response_confirm_upload_overload_2(self, client: Casedev) -> None: - with client.vault.with_streaming_response.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - vault = response.parse() - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_confirm_upload_overload_2(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.with_raw_response.confirm_upload( - object_id="objectId", - id="", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - client.vault.with_raw_response.confirm_upload( - object_id="", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - @parametrize def test_method_ingest(self, client: Casedev) -> None: vault = client.vault.ingest( @@ -481,9 +416,11 @@ def test_method_upload_with_all_params(self, client: Casedev) -> None: content_type="contentType", filename="filename", auto_index=True, + is_ai_generated=True, metadata={}, path="path", size_bytes=1, + idempotency_key="Idempotency-Key", ) assert_matches_type(VaultUploadResponse, vault, path=["response"]) @@ -736,32 +673,33 @@ async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: ) @parametrize - async def test_method_confirm_upload_overload_1(self, async_client: AsyncCasedev) -> None: + async def test_method_confirm_upload(self, async_client: AsyncCasedev) -> None: vault = await async_client.vault.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - async def test_method_confirm_upload_with_all_params_overload_1(self, async_client: AsyncCasedev) -> None: + async def test_method_confirm_upload_with_all_params(self, async_client: AsyncCasedev) -> None: vault = await async_client.vault.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, + auto_ingest=True, + error_code="errorCode", + error_message="errorMessage", etag="etag", + size_bytes=1, ) assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - async def test_raw_response_confirm_upload_overload_1(self, async_client: AsyncCasedev) -> None: + async def test_raw_response_confirm_upload(self, async_client: AsyncCasedev) -> None: response = await async_client.vault.with_raw_response.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) @@ -771,11 +709,10 @@ async def test_raw_response_confirm_upload_overload_1(self, async_client: AsyncC assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) @parametrize - async def test_streaming_response_confirm_upload_overload_1(self, async_client: AsyncCasedev) -> None: + async def test_streaming_response_confirm_upload(self, async_client: AsyncCasedev) -> None: async with async_client.vault.with_streaming_response.confirm_upload( object_id="objectId", id="id", - size_bytes=1, success=True, ) as response: assert not response.is_closed @@ -787,12 +724,11 @@ async def test_streaming_response_confirm_upload_overload_1(self, async_client: assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_confirm_upload_overload_1(self, async_client: AsyncCasedev) -> None: + async def test_path_params_confirm_upload(self, async_client: AsyncCasedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): await async_client.vault.with_raw_response.confirm_upload( object_id="objectId", id="", - size_bytes=1, success=True, ) @@ -800,73 +736,9 @@ async def test_path_params_confirm_upload_overload_1(self, async_client: AsyncCa await async_client.vault.with_raw_response.confirm_upload( object_id="", id="id", - size_bytes=1, success=True, ) - @parametrize - async def test_method_confirm_upload_overload_2(self, async_client: AsyncCasedev) -> None: - vault = await async_client.vault.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - @parametrize - async def test_raw_response_confirm_upload_overload_2(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.with_raw_response.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - vault = await response.parse() - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - @parametrize - async def test_streaming_response_confirm_upload_overload_2(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.with_streaming_response.confirm_upload( - object_id="objectId", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - vault = await response.parse() - assert_matches_type(VaultConfirmUploadResponse, vault, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_confirm_upload_overload_2(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.with_raw_response.confirm_upload( - object_id="objectId", - id="", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - await async_client.vault.with_raw_response.confirm_upload( - object_id="", - id="id", - error_code="errorCode", - error_message="errorMessage", - success=False, - ) - @parametrize async def test_method_ingest(self, async_client: AsyncCasedev) -> None: vault = await async_client.vault.ingest( @@ -984,9 +856,11 @@ async def test_method_upload_with_all_params(self, async_client: AsyncCasedev) - content_type="contentType", filename="filename", auto_index=True, + is_ai_generated=True, metadata={}, path="path", size_bytes=1, + idempotency_key="Idempotency-Key", ) assert_matches_type(VaultUploadResponse, vault, path=["response"]) diff --git a/tests/api_resources/translate/test_v1.py b/tests/api_resources/translate/test_v1.py index 3af69dc8..921b8c79 100644 --- a/tests/api_resources/translate/test_v1.py +++ b/tests/api_resources/translate/test_v1.py @@ -5,10 +5,18 @@ import os from typing import Any, cast +import httpx import pytest +from respx import MockRouter from casedev import Casedev, AsyncCasedev from tests.utils import assert_matches_type +from casedev._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, +) from casedev.types.translate import ( V1DetectResponse, V1TranslateResponse, @@ -130,6 +138,65 @@ def test_streaming_response_translate(self, client: Casedev) -> None: assert cast(Any, response.is_closed) is True + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_translate_document(self, client: Casedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + v1 = client.translate.v1.translate_document( + file=b"Example data", + target="es", + ) + assert v1.is_closed + assert v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_translate_document_with_all_params(self, client: Casedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + v1 = client.translate.v1.translate_document( + file=b"Example data", + target="es", + source="en", + ) + assert v1.is_closed + assert v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_translate_document(self, client: Casedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + v1 = client.translate.v1.with_raw_response.translate_document( + file=b"Example data", + target="es", + ) + + assert v1.is_closed is True + assert v1.http_request.headers.get("X-Stainless-Lang") == "python" + assert v1.json() == {"foo": "bar"} + assert isinstance(v1, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_translate_document(self, client: Casedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.translate.v1.with_streaming_response.translate_document( + file=b"Example data", + target="es", + ) as v1: + assert not v1.is_closed + assert v1.http_request.headers.get("X-Stainless-Lang") == "python" + + assert v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, StreamedBinaryAPIResponse) + + assert cast(Any, v1.is_closed) is True + class TestAsyncV1: parametrize = pytest.mark.parametrize( @@ -244,3 +311,66 @@ async def test_streaming_response_translate(self, async_client: AsyncCasedev) -> assert_matches_type(V1TranslateResponse, v1, path=["response"]) assert cast(Any, response.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_translate_document(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + v1 = await async_client.translate.v1.translate_document( + file=b"Example data", + target="es", + ) + assert v1.is_closed + assert await v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_translate_document_with_all_params( + self, async_client: AsyncCasedev, respx_mock: MockRouter + ) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + v1 = await async_client.translate.v1.translate_document( + file=b"Example data", + target="es", + source="en", + ) + assert v1.is_closed + assert await v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_translate_document(self, async_client: AsyncCasedev, respx_mock: MockRouter) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + v1 = await async_client.translate.v1.with_raw_response.translate_document( + file=b"Example data", + target="es", + ) + + assert v1.is_closed is True + assert v1.http_request.headers.get("X-Stainless-Lang") == "python" + assert await v1.json() == {"foo": "bar"} + assert isinstance(v1, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_translate_document( + self, async_client: AsyncCasedev, respx_mock: MockRouter + ) -> None: + respx_mock.post("/translate/v1/document").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.translate.v1.with_streaming_response.translate_document( + file=b"Example data", + target="es", + ) as v1: + assert not v1.is_closed + assert v1.http_request.headers.get("X-Stainless-Lang") == "python" + + assert await v1.json() == {"foo": "bar"} + assert cast(Any, v1.is_closed) is True + assert isinstance(v1, AsyncStreamedBinaryAPIResponse) + + assert cast(Any, v1.is_closed) is True diff --git a/tests/api_resources/usage/test_v1.py b/tests/api_resources/usage/test_v1.py index b793596a..4ee2a1f1 100644 --- a/tests/api_resources/usage/test_v1.py +++ b/tests/api_resources/usage/test_v1.py @@ -25,6 +25,8 @@ def test_method_retrieve(self, client: Casedev) -> None: def test_method_retrieve_with_all_params(self, client: Casedev) -> None: v1 = client.usage.v1.retrieve( granularity="summary", + group_by="lincSessionId", + linc_session_id="lincSessionId", period_end=parse_datetime("2019-12-27T18:11:19.117Z"), period_start=parse_datetime("2019-12-27T18:11:19.117Z"), ) @@ -65,6 +67,8 @@ async def test_method_retrieve(self, async_client: AsyncCasedev) -> None: async def test_method_retrieve_with_all_params(self, async_client: AsyncCasedev) -> None: v1 = await async_client.usage.v1.retrieve( granularity="summary", + group_by="lincSessionId", + linc_session_id="lincSessionId", period_end=parse_datetime("2019-12-27T18:11:19.117Z"), period_start=parse_datetime("2019-12-27T18:11:19.117Z"), ) diff --git a/tests/api_resources/vault/test_graphrag.py b/tests/api_resources/vault/test_graphrag.py deleted file mode 100644 index 7a36f4de..00000000 --- a/tests/api_resources/vault/test_graphrag.py +++ /dev/null @@ -1,272 +0,0 @@ -# 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 casedev import Casedev, AsyncCasedev -from tests.utils import assert_matches_type -from casedev.types.vault import GraphragInitResponse, GraphragGetStatsResponse, GraphragProcessObjectResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestGraphrag: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get_stats(self, client: Casedev) -> None: - graphrag = client.vault.graphrag.get_stats( - "id", - ) - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - @parametrize - def test_raw_response_get_stats(self, client: Casedev) -> None: - response = client.vault.graphrag.with_raw_response.get_stats( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = response.parse() - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - @parametrize - def test_streaming_response_get_stats(self, client: Casedev) -> None: - with client.vault.graphrag.with_streaming_response.get_stats( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = response.parse() - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_stats(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.graphrag.with_raw_response.get_stats( - "", - ) - - @parametrize - def test_method_init(self, client: Casedev) -> None: - graphrag = client.vault.graphrag.init( - "id", - ) - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - @parametrize - def test_raw_response_init(self, client: Casedev) -> None: - response = client.vault.graphrag.with_raw_response.init( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = response.parse() - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - @parametrize - def test_streaming_response_init(self, client: Casedev) -> None: - with client.vault.graphrag.with_streaming_response.init( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = response.parse() - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_init(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.graphrag.with_raw_response.init( - "", - ) - - @parametrize - def test_method_process_object(self, client: Casedev) -> None: - graphrag = client.vault.graphrag.process_object( - object_id="objectId", - id="id", - ) - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - @parametrize - def test_raw_response_process_object(self, client: Casedev) -> None: - response = client.vault.graphrag.with_raw_response.process_object( - object_id="objectId", - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = response.parse() - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - @parametrize - def test_streaming_response_process_object(self, client: Casedev) -> None: - with client.vault.graphrag.with_streaming_response.process_object( - object_id="objectId", - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = response.parse() - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_process_object(self, client: Casedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.graphrag.with_raw_response.process_object( - object_id="objectId", - id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - client.vault.graphrag.with_raw_response.process_object( - object_id="", - id="id", - ) - - -class TestAsyncGraphrag: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get_stats(self, async_client: AsyncCasedev) -> None: - graphrag = await async_client.vault.graphrag.get_stats( - "id", - ) - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - @parametrize - async def test_raw_response_get_stats(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.graphrag.with_raw_response.get_stats( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = await response.parse() - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - @parametrize - async def test_streaming_response_get_stats(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.graphrag.with_streaming_response.get_stats( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = await response.parse() - assert_matches_type(GraphragGetStatsResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_stats(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.graphrag.with_raw_response.get_stats( - "", - ) - - @parametrize - async def test_method_init(self, async_client: AsyncCasedev) -> None: - graphrag = await async_client.vault.graphrag.init( - "id", - ) - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - @parametrize - async def test_raw_response_init(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.graphrag.with_raw_response.init( - "id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = await response.parse() - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - @parametrize - async def test_streaming_response_init(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.graphrag.with_streaming_response.init( - "id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = await response.parse() - assert_matches_type(GraphragInitResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_init(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.graphrag.with_raw_response.init( - "", - ) - - @parametrize - async def test_method_process_object(self, async_client: AsyncCasedev) -> None: - graphrag = await async_client.vault.graphrag.process_object( - object_id="objectId", - id="id", - ) - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - @parametrize - async def test_raw_response_process_object(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.graphrag.with_raw_response.process_object( - object_id="objectId", - id="id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - graphrag = await response.parse() - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - @parametrize - async def test_streaming_response_process_object(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.graphrag.with_streaming_response.process_object( - object_id="objectId", - id="id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - graphrag = await response.parse() - assert_matches_type(GraphragProcessObjectResponse, graphrag, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_process_object(self, async_client: AsyncCasedev) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.graphrag.with_raw_response.process_object( - object_id="objectId", - id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - await async_client.vault.graphrag.with_raw_response.process_object( - object_id="", - id="id", - ) diff --git a/tests/api_resources/vault/test_multipart.py b/tests/api_resources/vault/test_multipart.py index 14eac091..29e3a5d8 100644 --- a/tests/api_resources/vault/test_multipart.py +++ b/tests/api_resources/vault/test_multipart.py @@ -9,7 +9,10 @@ from casedev import Casedev, AsyncCasedev from tests.utils import assert_matches_type -from casedev.types.vault import MultipartGetPartURLsResponse +from casedev.types.vault import ( + MultipartInitResponse, + MultipartGetPartURLsResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -63,6 +66,80 @@ def test_path_params_abort(self, client: Casedev) -> None: upload_id="uploadId", ) + @parametrize + def test_method_complete(self, client: Casedev) -> None: + multipart = client.vault.multipart.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + assert multipart is None + + @parametrize + def test_raw_response_complete(self, client: Casedev) -> None: + response = client.vault.multipart.with_raw_response.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + multipart = response.parse() + assert multipart is None + + @parametrize + def test_streaming_response_complete(self, client: Casedev) -> None: + with client.vault.multipart.with_streaming_response.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + multipart = response.parse() + assert multipart is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_complete(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.vault.multipart.with_raw_response.complete( + id="", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + @parametrize def test_method_get_part_urls(self, client: Casedev) -> None: multipart = client.vault.multipart.get_part_urls( @@ -133,6 +210,71 @@ def test_path_params_get_part_urls(self, client: Casedev) -> None: upload_id="uploadId", ) + @parametrize + def test_method_init(self, client: Casedev) -> None: + multipart = client.vault.multipart.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + def test_method_init_with_all_params(self, client: Casedev) -> None: + multipart = client.vault.multipart.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + auto_index=True, + is_ai_generated=True, + metadata={}, + part_size_bytes=5242880, + path="path", + ) + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + def test_raw_response_init(self, client: Casedev) -> None: + response = client.vault.multipart.with_raw_response.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + multipart = response.parse() + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + def test_streaming_response_init(self, client: Casedev) -> None: + with client.vault.multipart.with_streaming_response.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + multipart = response.parse() + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_init(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.vault.multipart.with_raw_response.init( + id="", + content_type="contentType", + filename="filename", + size_bytes=1, + ) + class TestAsyncMultipart: parametrize = pytest.mark.parametrize( @@ -185,6 +327,80 @@ async def test_path_params_abort(self, async_client: AsyncCasedev) -> None: upload_id="uploadId", ) + @parametrize + async def test_method_complete(self, async_client: AsyncCasedev) -> None: + multipart = await async_client.vault.multipart.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + assert multipart is None + + @parametrize + async def test_raw_response_complete(self, async_client: AsyncCasedev) -> None: + response = await async_client.vault.multipart.with_raw_response.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + multipart = await response.parse() + assert multipart is None + + @parametrize + async def test_streaming_response_complete(self, async_client: AsyncCasedev) -> None: + async with async_client.vault.multipart.with_streaming_response.complete( + id="id", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + multipart = await response.parse() + assert multipart is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_complete(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.vault.multipart.with_raw_response.complete( + id="", + object_id="objectId", + parts=[ + { + "etag": "etag", + "part_number": 1, + } + ], + size_bytes=1, + upload_id="uploadId", + ) + @parametrize async def test_method_get_part_urls(self, async_client: AsyncCasedev) -> None: multipart = await async_client.vault.multipart.get_part_urls( @@ -254,3 +470,68 @@ async def test_path_params_get_part_urls(self, async_client: AsyncCasedev) -> No ], upload_id="uploadId", ) + + @parametrize + async def test_method_init(self, async_client: AsyncCasedev) -> None: + multipart = await async_client.vault.multipart.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + async def test_method_init_with_all_params(self, async_client: AsyncCasedev) -> None: + multipart = await async_client.vault.multipart.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + auto_index=True, + is_ai_generated=True, + metadata={}, + part_size_bytes=5242880, + path="path", + ) + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + async def test_raw_response_init(self, async_client: AsyncCasedev) -> None: + response = await async_client.vault.multipart.with_raw_response.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + multipart = await response.parse() + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + @parametrize + async def test_streaming_response_init(self, async_client: AsyncCasedev) -> None: + async with async_client.vault.multipart.with_streaming_response.init( + id="id", + content_type="contentType", + filename="filename", + size_bytes=1, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + multipart = await response.parse() + assert_matches_type(MultipartInitResponse, multipart, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_init(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.vault.multipart.with_raw_response.init( + id="", + content_type="contentType", + filename="filename", + size_bytes=1, + ) diff --git a/tests/api_resources/vault/test_objects.py b/tests/api_resources/vault/test_objects.py index ddf0e8bf..d47f7070 100644 --- a/tests/api_resources/vault/test_objects.py +++ b/tests/api_resources/vault/test_objects.py @@ -19,6 +19,8 @@ ) from casedev.types.vault import ( ObjectListResponse, + ObjectMergeResponse, + ObjectAppendResponse, ObjectDeleteResponse, ObjectUpdateResponse, ObjectGetTextResponse, @@ -26,7 +28,6 @@ ObjectRetrieveResponse, ObjectGetChunksResponse, ObjectGetOcrWordsResponse, - ObjectGetSummarizeJobResponse, ObjectCreatePresignedURLResponse, ) @@ -146,14 +147,22 @@ def test_path_params_update(self, client: Casedev) -> None: @parametrize def test_method_list(self, client: Casedev) -> None: object_ = client.vault.objects.list( - "id", + id="id", + ) + assert_matches_type(ObjectListResponse, object_, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Casedev) -> None: + object_ = client.vault.objects.list( + id="id", + include_unconfirmed=True, ) assert_matches_type(ObjectListResponse, object_, path=["response"]) @parametrize def test_raw_response_list(self, client: Casedev) -> None: response = client.vault.objects.with_raw_response.list( - "id", + id="id", ) assert response.is_closed is True @@ -164,7 +173,7 @@ def test_raw_response_list(self, client: Casedev) -> None: @parametrize def test_streaming_response_list(self, client: Casedev) -> None: with client.vault.objects.with_streaming_response.list( - "id", + id="id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -178,7 +187,7 @@ def test_streaming_response_list(self, client: Casedev) -> None: def test_path_params_list(self, client: Casedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): client.vault.objects.with_raw_response.list( - "", + id="", ) @parametrize @@ -238,6 +247,78 @@ def test_path_params_delete(self, client: Casedev) -> None: id="id", ) + @parametrize + def test_method_append(self, client: Casedev) -> None: + object_ = client.vault.objects.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + def test_method_append_with_all_params(self, client: Casedev) -> None: + object_ = client.vault.objects.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + back_links=True, + back_links_text="backLinksText", + bates={ + "enabled": True, + "pad_to": 0, + "prefix": "prefix", + "start": 1, + "suffix": "suffix", + }, + rewrite_links=True, + ) + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + def test_raw_response_append(self, client: Casedev) -> None: + response = client.vault.objects.with_raw_response.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + object_ = response.parse() + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + def test_streaming_response_append(self, client: Casedev) -> None: + with client.vault.objects.with_streaming_response.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + object_ = response.parse() + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_append(self, client: Casedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.vault.objects.with_raw_response.append( + object_id="objectId", + id="", + append_object_ids=["string"], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): + client.vault.objects.with_raw_response.append( + object_id="", + id="id", + append_object_ids=["string"], + ) + @parametrize def test_method_create_presigned_url(self, client: Casedev) -> None: object_ = client.vault.objects.create_presigned_url( @@ -540,111 +621,123 @@ def test_path_params_get_pages(self, client: Casedev) -> None: ) @parametrize - def test_method_get_summarize_job(self, client: Casedev) -> None: - object_ = client.vault.objects.get_summarize_job( - job_id="jobId", - id="id", + def test_method_get_text(self, client: Casedev) -> None: + object_ = client.vault.objects.get_text( object_id="objectId", + id="id", ) - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) @parametrize - def test_raw_response_get_summarize_job(self, client: Casedev) -> None: - response = client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="id", + def test_raw_response_get_text(self, client: Casedev) -> None: + response = client.vault.objects.with_raw_response.get_text( object_id="objectId", + id="id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = response.parse() - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) @parametrize - def test_streaming_response_get_summarize_job(self, client: Casedev) -> None: - with client.vault.objects.with_streaming_response.get_summarize_job( - job_id="jobId", - id="id", + def test_streaming_response_get_text(self, client: Casedev) -> None: + with client.vault.objects.with_streaming_response.get_text( object_id="objectId", + id="id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = response.parse() - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_summarize_job(self, client: Casedev) -> None: + def test_path_params_get_text(self, client: Casedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="", + client.vault.objects.with_raw_response.get_text( object_id="objectId", + id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="id", + client.vault.objects.with_raw_response.get_text( object_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - client.vault.objects.with_raw_response.get_summarize_job( - job_id="", id="id", - object_id="objectId", ) @parametrize - def test_method_get_text(self, client: Casedev) -> None: - object_ = client.vault.objects.get_text( - object_id="objectId", + def test_method_merge(self, client: Casedev) -> None: + object_ = client.vault.objects.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) + + @parametrize + def test_method_merge_with_all_params(self, client: Casedev) -> None: + object_ = client.vault.objects.merge( + id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", + bates={ + "pad_to": 0, + "prefix": "prefix", + "start": 1, + "suffix": "suffix", + }, + client_reference="clientReference", + ) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) @parametrize - def test_raw_response_get_text(self, client: Casedev) -> None: - response = client.vault.objects.with_raw_response.get_text( - object_id="objectId", + def test_raw_response_merge(self, client: Casedev) -> None: + response = client.vault.objects.with_raw_response.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = response.parse() - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) @parametrize - def test_streaming_response_get_text(self, client: Casedev) -> None: - with client.vault.objects.with_streaming_response.get_text( - object_id="objectId", + def test_streaming_response_merge(self, client: Casedev) -> None: + with client.vault.objects.with_streaming_response.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = response.parse() - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_get_text(self, client: Casedev) -> None: + def test_path_params_merge(self, client: Casedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.vault.objects.with_raw_response.get_text( - object_id="objectId", + client.vault.objects.with_raw_response.merge( id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - client.vault.objects.with_raw_response.get_text( - object_id="", - id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) @@ -763,14 +856,22 @@ async def test_path_params_update(self, async_client: AsyncCasedev) -> None: @parametrize async def test_method_list(self, async_client: AsyncCasedev) -> None: object_ = await async_client.vault.objects.list( - "id", + id="id", + ) + assert_matches_type(ObjectListResponse, object_, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.list( + id="id", + include_unconfirmed=True, ) assert_matches_type(ObjectListResponse, object_, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: response = await async_client.vault.objects.with_raw_response.list( - "id", + id="id", ) assert response.is_closed is True @@ -781,7 +882,7 @@ async def test_raw_response_list(self, async_client: AsyncCasedev) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None: async with async_client.vault.objects.with_streaming_response.list( - "id", + id="id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -795,7 +896,7 @@ async def test_streaming_response_list(self, async_client: AsyncCasedev) -> None async def test_path_params_list(self, async_client: AsyncCasedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): await async_client.vault.objects.with_raw_response.list( - "", + id="", ) @parametrize @@ -855,6 +956,78 @@ async def test_path_params_delete(self, async_client: AsyncCasedev) -> None: id="id", ) + @parametrize + async def test_method_append(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + async def test_method_append_with_all_params(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + back_links=True, + back_links_text="backLinksText", + bates={ + "enabled": True, + "pad_to": 0, + "prefix": "prefix", + "start": 1, + "suffix": "suffix", + }, + rewrite_links=True, + ) + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + async def test_raw_response_append(self, async_client: AsyncCasedev) -> None: + response = await async_client.vault.objects.with_raw_response.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + object_ = await response.parse() + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + @parametrize + async def test_streaming_response_append(self, async_client: AsyncCasedev) -> None: + async with async_client.vault.objects.with_streaming_response.append( + object_id="objectId", + id="id", + append_object_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + object_ = await response.parse() + assert_matches_type(ObjectAppendResponse, object_, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_append(self, async_client: AsyncCasedev) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.vault.objects.with_raw_response.append( + object_id="objectId", + id="", + append_object_ids=["string"], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): + await async_client.vault.objects.with_raw_response.append( + object_id="", + id="id", + append_object_ids=["string"], + ) + @parametrize async def test_method_create_presigned_url(self, async_client: AsyncCasedev) -> None: object_ = await async_client.vault.objects.create_presigned_url( @@ -1157,109 +1330,121 @@ async def test_path_params_get_pages(self, async_client: AsyncCasedev) -> None: ) @parametrize - async def test_method_get_summarize_job(self, async_client: AsyncCasedev) -> None: - object_ = await async_client.vault.objects.get_summarize_job( - job_id="jobId", - id="id", + async def test_method_get_text(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.get_text( object_id="objectId", + id="id", ) - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) @parametrize - async def test_raw_response_get_summarize_job(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="id", + async def test_raw_response_get_text(self, async_client: AsyncCasedev) -> None: + response = await async_client.vault.objects.with_raw_response.get_text( object_id="objectId", + id="id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = await response.parse() - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) @parametrize - async def test_streaming_response_get_summarize_job(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.objects.with_streaming_response.get_summarize_job( - job_id="jobId", - id="id", + async def test_streaming_response_get_text(self, async_client: AsyncCasedev) -> None: + async with async_client.vault.objects.with_streaming_response.get_text( object_id="objectId", + id="id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = await response.parse() - assert_matches_type(ObjectGetSummarizeJobResponse, object_, path=["response"]) + assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_summarize_job(self, async_client: AsyncCasedev) -> None: + async def test_path_params_get_text(self, async_client: AsyncCasedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="", + await async_client.vault.objects.with_raw_response.get_text( object_id="objectId", + id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - await async_client.vault.objects.with_raw_response.get_summarize_job( - job_id="jobId", - id="id", + await async_client.vault.objects.with_raw_response.get_text( object_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `job_id` but received ''"): - await async_client.vault.objects.with_raw_response.get_summarize_job( - job_id="", id="id", - object_id="objectId", ) @parametrize - async def test_method_get_text(self, async_client: AsyncCasedev) -> None: - object_ = await async_client.vault.objects.get_text( - object_id="objectId", + async def test_method_merge(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) + + @parametrize + async def test_method_merge_with_all_params(self, async_client: AsyncCasedev) -> None: + object_ = await async_client.vault.objects.merge( + id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", + bates={ + "pad_to": 0, + "prefix": "prefix", + "start": 1, + "suffix": "suffix", + }, + client_reference="clientReference", + ) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) @parametrize - async def test_raw_response_get_text(self, async_client: AsyncCasedev) -> None: - response = await async_client.vault.objects.with_raw_response.get_text( - object_id="objectId", + async def test_raw_response_merge(self, async_client: AsyncCasedev) -> None: + response = await async_client.vault.objects.with_raw_response.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = await response.parse() - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) @parametrize - async def test_streaming_response_get_text(self, async_client: AsyncCasedev) -> None: - async with async_client.vault.objects.with_streaming_response.get_text( - object_id="objectId", + async def test_streaming_response_merge(self, async_client: AsyncCasedev) -> None: + async with async_client.vault.objects.with_streaming_response.merge( id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" object_ = await response.parse() - assert_matches_type(ObjectGetTextResponse, object_, path=["response"]) + assert_matches_type(ObjectMergeResponse, object_, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_get_text(self, async_client: AsyncCasedev) -> None: + async def test_path_params_merge(self, async_client: AsyncCasedev) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.vault.objects.with_raw_response.get_text( - object_id="objectId", + await async_client.vault.objects.with_raw_response.merge( id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `object_id` but received ''"): - await async_client.vault.objects.with_raw_response.get_text( - object_id="", - id="id", + filename="filename", + source_object_ids=["string"], + source_rendition="original", + idempotency_key="x", )