diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bfc26f9..75ec52f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.2.0" + ".": "2.3.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index c2cc39a..1ba5348 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 29 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-ecb277557634e2f0838ea196e2b21f11924f65e133c7977e8c2e1a603b8df466.yml -openapi_spec_hash: 798ce4cb042389a1179bf9af6fc1173d -config_hash: ff35e224e809656528c44163aa41bebd +configured_endpoints: 30 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-c90f13e3cf4b9ae6a1d8f22c0e7285ab12d412d3a659a51a247a97adc7f08121.yml +openapi_spec_hash: bf7879be38ebf3397a939c80b261a47a +config_hash: daabb160675d86b354711da1e77e5129 diff --git a/CHANGELOG.md b/CHANGELOG.md index 988cfad..2f0de6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 2.3.0 (2026-07-12) + +Full Changelog: [v2.2.0...v2.3.0](https://github.com/context-dot-dev/context-python-sdk/compare/v2.2.0...v2.3.0) + +### Features + +* **api:** api update ([dac3f38](https://github.com/context-dot-dev/context-python-sdk/commit/dac3f38751139f40031ab70750a7831cbb9f42be)) +* **api:** api update ([921eaa8](https://github.com/context-dot-dev/context-python-sdk/commit/921eaa8d1682df7ba9d70855fcb700b336465c7c)) +* **api:** api update ([3e75380](https://github.com/context-dot-dev/context-python-sdk/commit/3e753806bd5077a81f62d797021c15067a0daffe)) +* **api:** api update ([3b9e64f](https://github.com/context-dot-dev/context-python-sdk/commit/3b9e64f5dddd1992ea79f0dc88da7f3131f7e43d)) +* **api:** api update ([9f486e7](https://github.com/context-dot-dev/context-python-sdk/commit/9f486e7d1067b55375977f6fc1f2520093eeb4d6)) +* **api:** api update ([94c1bb6](https://github.com/context-dot-dev/context-python-sdk/commit/94c1bb60cde333694a5f62b2526603b79d8fd62a)) +* **api:** manual updates ([538a766](https://github.com/context-dot-dev/context-python-sdk/commit/538a76606adf7e885ad2f953ea62ae2ac8b9e29a)) + ## 2.2.0 (2026-07-10) Full Changelog: [v2.1.0...v2.2.0](https://github.com/context-dot-dev/context-python-sdk/compare/v2.1.0...v2.2.0) diff --git a/api.md b/api.md index 1754626..c7ab5f7 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,15 @@ +# Parse + +Types: + +```python +from context.dev.types import ParseHandleResponse +``` + +Methods: + +- client.parse.handle(body, \*\*params) -> ParseHandleResponse + # Web Types: @@ -89,6 +101,7 @@ Types: ```python from context.dev.types import ( + WebhookDelivery, MonitorCreateResponse, MonitorRetrieveResponse, MonitorUpdateResponse, diff --git a/pyproject.toml b/pyproject.toml index 87342b0..56109df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "context.dev" -version = "2.2.0" +version = "2.3.0" description = "The official Python library for the context.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/context/dev/_client.py b/src/context/dev/_client.py index e0b4af5..800374f 100644 --- a/src/context/dev/_client.py +++ b/src/context/dev/_client.py @@ -35,10 +35,11 @@ ) if TYPE_CHECKING: - from .resources import ai, web, brand, utility, industry, monitors + from .resources import ai, web, brand, parse, utility, industry, monitors from .resources.ai import AIResource, AsyncAIResource from .resources.web import WebResource, AsyncWebResource from .resources.brand import BrandResource, AsyncBrandResource + from .resources.parse import ParseResource, AsyncParseResource from .resources.utility import UtilityResource, AsyncUtilityResource from .resources.industry import IndustryResource, AsyncIndustryResource from .resources.monitors import MonitorsResource, AsyncMonitorsResource @@ -119,6 +120,12 @@ def __init__( _strict_response_validation=_strict_response_validation, ) + @cached_property + def parse(self) -> ParseResource: + from .resources.parse import ParseResource + + return ParseResource(self) + @cached_property def web(self) -> WebResource: from .resources.web import WebResource @@ -152,7 +159,7 @@ def utility(self) -> UtilityResource: @cached_property def monitors(self) -> MonitorsResource: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import MonitorsResource @@ -335,6 +342,12 @@ def __init__( _strict_response_validation=_strict_response_validation, ) + @cached_property + def parse(self) -> AsyncParseResource: + from .resources.parse import AsyncParseResource + + return AsyncParseResource(self) + @cached_property def web(self) -> AsyncWebResource: from .resources.web import AsyncWebResource @@ -368,7 +381,7 @@ def utility(self) -> AsyncUtilityResource: @cached_property def monitors(self) -> AsyncMonitorsResource: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import AsyncMonitorsResource @@ -493,6 +506,12 @@ class ContextDevWithRawResponse: def __init__(self, client: ContextDev) -> None: self._client = client + @cached_property + def parse(self) -> parse.ParseResourceWithRawResponse: + from .resources.parse import ParseResourceWithRawResponse + + return ParseResourceWithRawResponse(self._client.parse) + @cached_property def web(self) -> web.WebResourceWithRawResponse: from .resources.web import WebResourceWithRawResponse @@ -526,7 +545,7 @@ def utility(self) -> utility.UtilityResourceWithRawResponse: @cached_property def monitors(self) -> monitors.MonitorsResourceWithRawResponse: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import MonitorsResourceWithRawResponse @@ -539,6 +558,12 @@ class AsyncContextDevWithRawResponse: def __init__(self, client: AsyncContextDev) -> None: self._client = client + @cached_property + def parse(self) -> parse.AsyncParseResourceWithRawResponse: + from .resources.parse import AsyncParseResourceWithRawResponse + + return AsyncParseResourceWithRawResponse(self._client.parse) + @cached_property def web(self) -> web.AsyncWebResourceWithRawResponse: from .resources.web import AsyncWebResourceWithRawResponse @@ -572,7 +597,7 @@ def utility(self) -> utility.AsyncUtilityResourceWithRawResponse: @cached_property def monitors(self) -> monitors.AsyncMonitorsResourceWithRawResponse: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import AsyncMonitorsResourceWithRawResponse @@ -585,6 +610,12 @@ class ContextDevWithStreamedResponse: def __init__(self, client: ContextDev) -> None: self._client = client + @cached_property + def parse(self) -> parse.ParseResourceWithStreamingResponse: + from .resources.parse import ParseResourceWithStreamingResponse + + return ParseResourceWithStreamingResponse(self._client.parse) + @cached_property def web(self) -> web.WebResourceWithStreamingResponse: from .resources.web import WebResourceWithStreamingResponse @@ -618,7 +649,7 @@ def utility(self) -> utility.UtilityResourceWithStreamingResponse: @cached_property def monitors(self) -> monitors.MonitorsResourceWithStreamingResponse: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import MonitorsResourceWithStreamingResponse @@ -631,6 +662,12 @@ class AsyncContextDevWithStreamedResponse: def __init__(self, client: AsyncContextDev) -> None: self._client = client + @cached_property + def parse(self) -> parse.AsyncParseResourceWithStreamingResponse: + from .resources.parse import AsyncParseResourceWithStreamingResponse + + return AsyncParseResourceWithStreamingResponse(self._client.parse) + @cached_property def web(self) -> web.AsyncWebResourceWithStreamingResponse: from .resources.web import AsyncWebResourceWithStreamingResponse @@ -664,7 +701,7 @@ def utility(self) -> utility.AsyncUtilityResourceWithStreamingResponse: @cached_property def monitors(self) -> monitors.AsyncMonitorsResourceWithStreamingResponse: """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ from .resources.monitors import AsyncMonitorsResourceWithStreamingResponse diff --git a/src/context/dev/_version.py b/src/context/dev/_version.py index b91150a..b5761aa 100644 --- a/src/context/dev/_version.py +++ b/src/context/dev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "context.dev" -__version__ = "2.2.0" # x-release-please-version +__version__ = "2.3.0" # x-release-please-version diff --git a/src/context/dev/resources/__init__.py b/src/context/dev/resources/__init__.py index b0af419..12b45f9 100644 --- a/src/context/dev/resources/__init__.py +++ b/src/context/dev/resources/__init__.py @@ -24,6 +24,14 @@ BrandResourceWithStreamingResponse, AsyncBrandResourceWithStreamingResponse, ) +from .parse import ( + ParseResource, + AsyncParseResource, + ParseResourceWithRawResponse, + AsyncParseResourceWithRawResponse, + ParseResourceWithStreamingResponse, + AsyncParseResourceWithStreamingResponse, +) from .utility import ( UtilityResource, AsyncUtilityResource, @@ -50,6 +58,12 @@ ) __all__ = [ + "ParseResource", + "AsyncParseResource", + "ParseResourceWithRawResponse", + "AsyncParseResourceWithRawResponse", + "ParseResourceWithStreamingResponse", + "AsyncParseResourceWithStreamingResponse", "WebResource", "AsyncWebResource", "WebResourceWithRawResponse", diff --git a/src/context/dev/resources/monitors.py b/src/context/dev/resources/monitors.py index 64ec92a..cd4bb61 100644 --- a/src/context/dev/resources/monitors.py +++ b/src/context/dev/resources/monitors.py @@ -45,7 +45,7 @@ class MonitorsResource(SyncAPIResource): """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ @cached_property @@ -622,7 +622,7 @@ def run( class AsyncMonitorsResource(AsyncAPIResource): """ - Monitor pages, sitemaps, and extracted website data for exact or semantic changes. The change.detected webhook payload is documented by the MonitorsChangeDetectedWebhookPayload schema. + Monitor pages, sitemaps, and extracted website data for exact or semantic changes. Webhook payloads are documented by the MonitorsChangeDetectedWebhookPayload and MonitorsRunCompletedWebhookPayload schemas. """ @cached_property diff --git a/src/context/dev/resources/parse.py b/src/context/dev/resources/parse.py new file mode 100644 index 0000000..16aa7a0 --- /dev/null +++ b/src/context/dev/resources/parse.py @@ -0,0 +1,289 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os + +import httpx + +from ..types import parse_handle_params +from .._files import read_file_content, async_read_file_content +from .._types import ( + Body, + Omit, + Query, + Headers, + NotGiven, + BinaryTypes, + FileContent, + AsyncBinaryTypes, + 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.parse_handle_response import ParseHandleResponse + +__all__ = ["ParseResource", "AsyncParseResource"] + + +class ParseResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ParseResourceWithRawResponse: + """ + 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/context-dot-dev/context-python-sdk#accessing-raw-response-data-eg-headers + """ + return ParseResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ParseResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/context-dot-dev/context-python-sdk#with_streaming_response + """ + return ParseResourceWithStreamingResponse(self) + + def handle( + self, + body: FileContent | BinaryTypes, + *, + base_url: str | Omit = omit, + extension: str | Omit = omit, + filename: str | Omit = omit, + include_images: bool | Omit = omit, + include_links: bool | Omit = omit, + ocr: bool | Omit = omit, + pdf_end: int | Omit = omit, + pdf_start: int | Omit = omit, + shorten_base64_images: bool | Omit = omit, + use_main_content_only: 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, + ) -> ParseHandleResponse: + """ + Converts raw text, source code, web/data, PDF, Microsoft Office, and image bytes + into LLM-usable Markdown. + + Args: + base_url: Optional HTTP(S) source document URL used to resolve relative links and image + references. Relative references remain relative when omitted. + + extension: Optional file extension hint, such as pdf, docx, xlsx, pptx, html, json, csv, + md, py, rtf, jpg, png, or txt. + + filename: Optional filename hint used to infer the extension when extension is omitted. + + include_images: Include image references in Markdown output + + include_links: Preserve hyperlinks in Markdown output + + ocr: When true for PDF inputs, detect and OCR images embedded in the selected pages, + inserting recognized text at each image's position in page reading order while + preserving the PDF text layer. pdfStart/pdfEnd limit the inclusive page range. + This is separate from automatic scanned-PDF OCR fallback. + + pdf_end: Last 1-based PDF page to parse. When omitted, parsing ends at the last page. + Must be greater than or equal to pdfStart when both are provided. + + pdf_start: First 1-based PDF page to parse. When omitted, parsing starts at the first page. + + shorten_base64_images: Shorten base64-encoded image data in the Markdown output + + use_main_content_only: Extract only the main content from HTML-like inputs + + 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 = {"Content-Type": "application/octet-stream", **(extra_headers or {})} + return self._post( + "/parse", + content=read_file_content(body) if isinstance(body, os.PathLike) else body, + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "base_url": base_url, + "extension": extension, + "filename": filename, + "include_images": include_images, + "include_links": include_links, + "ocr": ocr, + "pdf_end": pdf_end, + "pdf_start": pdf_start, + "shorten_base64_images": shorten_base64_images, + "use_main_content_only": use_main_content_only, + }, + parse_handle_params.ParseHandleParams, + ), + ), + cast_to=ParseHandleResponse, + ) + + +class AsyncParseResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncParseResourceWithRawResponse: + """ + 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/context-dot-dev/context-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncParseResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncParseResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/context-dot-dev/context-python-sdk#with_streaming_response + """ + return AsyncParseResourceWithStreamingResponse(self) + + async def handle( + self, + body: FileContent | AsyncBinaryTypes, + *, + base_url: str | Omit = omit, + extension: str | Omit = omit, + filename: str | Omit = omit, + include_images: bool | Omit = omit, + include_links: bool | Omit = omit, + ocr: bool | Omit = omit, + pdf_end: int | Omit = omit, + pdf_start: int | Omit = omit, + shorten_base64_images: bool | Omit = omit, + use_main_content_only: 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, + ) -> ParseHandleResponse: + """ + Converts raw text, source code, web/data, PDF, Microsoft Office, and image bytes + into LLM-usable Markdown. + + Args: + base_url: Optional HTTP(S) source document URL used to resolve relative links and image + references. Relative references remain relative when omitted. + + extension: Optional file extension hint, such as pdf, docx, xlsx, pptx, html, json, csv, + md, py, rtf, jpg, png, or txt. + + filename: Optional filename hint used to infer the extension when extension is omitted. + + include_images: Include image references in Markdown output + + include_links: Preserve hyperlinks in Markdown output + + ocr: When true for PDF inputs, detect and OCR images embedded in the selected pages, + inserting recognized text at each image's position in page reading order while + preserving the PDF text layer. pdfStart/pdfEnd limit the inclusive page range. + This is separate from automatic scanned-PDF OCR fallback. + + pdf_end: Last 1-based PDF page to parse. When omitted, parsing ends at the last page. + Must be greater than or equal to pdfStart when both are provided. + + pdf_start: First 1-based PDF page to parse. When omitted, parsing starts at the first page. + + shorten_base64_images: Shorten base64-encoded image data in the Markdown output + + use_main_content_only: Extract only the main content from HTML-like inputs + + 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 = {"Content-Type": "application/octet-stream", **(extra_headers or {})} + return await self._post( + "/parse", + content=await async_read_file_content(body) if isinstance(body, os.PathLike) else body, + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "base_url": base_url, + "extension": extension, + "filename": filename, + "include_images": include_images, + "include_links": include_links, + "ocr": ocr, + "pdf_end": pdf_end, + "pdf_start": pdf_start, + "shorten_base64_images": shorten_base64_images, + "use_main_content_only": use_main_content_only, + }, + parse_handle_params.ParseHandleParams, + ), + ), + cast_to=ParseHandleResponse, + ) + + +class ParseResourceWithRawResponse: + def __init__(self, parse: ParseResource) -> None: + self._parse = parse + + self.handle = to_raw_response_wrapper( + parse.handle, + ) + + +class AsyncParseResourceWithRawResponse: + def __init__(self, parse: AsyncParseResource) -> None: + self._parse = parse + + self.handle = async_to_raw_response_wrapper( + parse.handle, + ) + + +class ParseResourceWithStreamingResponse: + def __init__(self, parse: ParseResource) -> None: + self._parse = parse + + self.handle = to_streamed_response_wrapper( + parse.handle, + ) + + +class AsyncParseResourceWithStreamingResponse: + def __init__(self, parse: AsyncParseResource) -> None: + self._parse = parse + + self.handle = async_to_streamed_response_wrapper( + parse.handle, + ) diff --git a/src/context/dev/resources/web.py b/src/context/dev/resources/web.py index 00bc95e..8a06e27 100644 --- a/src/context/dev/resources/web.py +++ b/src/context/dev/resources/web.py @@ -1264,8 +1264,8 @@ def web_crawl_md( max_pages: Maximum number of pages to crawl. Hard cap: 500. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in @@ -1585,8 +1585,8 @@ def web_scrape_html( younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before extracting HTML. Defaults to false. This adds a bit of latency in exchange for @@ -1949,8 +1949,24 @@ def web_scrape_md( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WebWebScrapeMdResponse: - """ - Scrapes the given URL into LLM usable Markdown. + """Scrapes the given URL into LLM usable Markdown. + + Inspect key_metadata on JSON + responses from a recognized API key; use error_code to distinguish stable + failure categories. + + ### Billing & errors + + | HTTP status | Billed? | Meaning | + | ----------- | -------------- | ---------------------------------------------------------------------------------------- | + | 200 | Yes — 1 credit | Successful scrape, including a zero-length result when includeSelectors matched nothing | + | 400 | No | Invalid input, skipped PDF, or the page could not be scraped | + | 401 / 403 | No | Invalid/disabled key, insufficient permissions, or credits exhausted; inspect error_code | + | 404 | No | Target page returned or fingerprinted as not found | + | 408 | No | Request timed out | + | 415 | No | Unsupported content type | + | 429 | No | Per-minute rate limit exceeded; honor Retry-After | + | 500 | No | Internal error | Args: url: Full URL to scrape into LLM usable Markdown (must include http:// or https:// @@ -1981,8 +1997,8 @@ def web_scrape_md( younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before converting to Markdown. Defaults to false. This adds a bit of latency in @@ -3322,8 +3338,8 @@ async def web_crawl_md( max_pages: Maximum number of pages to crawl. Hard cap: 500. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in @@ -3643,8 +3659,8 @@ async def web_scrape_html( younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before extracting HTML. Defaults to false. This adds a bit of latency in exchange for @@ -4007,8 +4023,24 @@ async def web_scrape_md( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WebWebScrapeMdResponse: - """ - Scrapes the given URL into LLM usable Markdown. + """Scrapes the given URL into LLM usable Markdown. + + Inspect key_metadata on JSON + responses from a recognized API key; use error_code to distinguish stable + failure categories. + + ### Billing & errors + + | HTTP status | Billed? | Meaning | + | ----------- | -------------- | ---------------------------------------------------------------------------------------- | + | 200 | Yes — 1 credit | Successful scrape, including a zero-length result when includeSelectors matched nothing | + | 400 | No | Invalid input, skipped PDF, or the page could not be scraped | + | 401 / 403 | No | Invalid/disabled key, insufficient permissions, or credits exhausted; inspect error_code | + | 404 | No | Target page returned or fingerprinted as not found | + | 408 | No | Request timed out | + | 415 | No | Unsupported content type | + | 429 | No | Per-minute rate limit exceeded; honor Retry-After | + | 500 | No | Internal error | Args: url: Full URL to scrape into LLM usable Markdown (must include http:// or https:// @@ -4039,8 +4071,8 @@ async def web_scrape_md( younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. - pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an - inclusive 1-based page range. + pdf: PDF parsing controls. Use start/end to limit text extraction and embedded-image + detection/OCR to an inclusive 1-based page range. settle_animations: When true, waits briefly for CSS and transition animations to settle before converting to Markdown. Defaults to false. This adds a bit of latency in diff --git a/src/context/dev/types/__init__.py b/src/context/dev/types/__init__.py index 654f36e..2a14820 100644 --- a/src/context/dev/types/__init__.py +++ b/src/context/dev/types/__init__.py @@ -2,9 +2,11 @@ from __future__ import annotations +from .webhook_delivery import WebhookDelivery as WebhookDelivery from .web_search_params import WebSearchParams as WebSearchParams from .web_extract_params import WebExtractParams as WebExtractParams from .monitor_list_params import MonitorListParams as MonitorListParams +from .parse_handle_params import ParseHandleParams as ParseHandleParams from .web_search_response import WebSearchResponse as WebSearchResponse from .monitor_run_response import MonitorRunResponse as MonitorRunResponse from .web_extract_response import WebExtractResponse as WebExtractResponse @@ -12,6 +14,7 @@ from .monitor_create_params import MonitorCreateParams as MonitorCreateParams from .monitor_list_response import MonitorListResponse as MonitorListResponse from .monitor_update_params import MonitorUpdateParams as MonitorUpdateParams +from .parse_handle_response import ParseHandleResponse as ParseHandleResponse from .web_screenshot_params import WebScreenshotParams as WebScreenshotParams from .brand_retrieve_response import BrandRetrieveResponse as BrandRetrieveResponse from .monitor_create_response import MonitorCreateResponse as MonitorCreateResponse diff --git a/src/context/dev/types/monitor_create_params.py b/src/context/dev/types/monitor_create_params.py index 40813ad..0fa626e 100644 --- a/src/context/dev/types/monitor_create_params.py +++ b/src/context/dev/types/monitor_create_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .._types import SequenceNotStr @@ -168,4 +168,12 @@ class TargetMonitorsExtractTarget(TypedDict, total=False): class Webhook(TypedDict, total=False): url: Required[str] - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: List[Literal["change.detected", "run.completed"]] + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ diff --git a/src/context/dev/types/monitor_create_response.py b/src/context/dev/types/monitor_create_response.py index 76ef2ea..d42c0a1 100644 --- a/src/context/dev/types/monitor_create_response.py +++ b/src/context/dev/types/monitor_create_response.py @@ -25,6 +25,7 @@ "BaselineMonitorsExtractBaseline", "LastError", "Webhook", + "WebhookFailure", ] @@ -208,7 +209,15 @@ class LastError(BaseModel): class Webhook(BaseModel): url: str - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: Optional[List[Literal["change.detected", "run.completed"]]] = None + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ secret: Optional[str] = None """Signing secret used to verify webhook authenticity. @@ -220,6 +229,27 @@ class Webhook(BaseModel): """ +class WebhookFailure(BaseModel): + """ + Present while webhook deliveries are failing consecutively; null when deliveries are healthy or no webhook is configured. Cleared on the next successful delivery and when the webhook URL changes. + """ + + consecutive_failures: int + """Number of consecutive delivery attempts that did not succeed.""" + + last_failed_at: datetime + + last_message: str + """Human-readable description of the most recent failure.""" + + last_status: Literal["rejected", "failed", "skipped_unsafe_url"] + """Outcome of the most recent failed delivery. + + rejected means a non-2xx response; failed means no HTTP response was received; + skipped_unsafe_url means the URL failed the public-endpoint safety check. + """ + + class MonitorCreateResponse(BaseModel): """A web monitor. @@ -285,3 +315,10 @@ class MonitorCreateResponse(BaseModel): """User-defined tags for grouping and filtering monitors and their changes.""" webhook: Optional[Webhook] = None + + webhook_failure: Optional[WebhookFailure] = None + """ + Present while webhook deliveries are failing consecutively; null when deliveries + are healthy or no webhook is configured. Cleared on the next successful delivery + and when the webhook URL changes. + """ diff --git a/src/context/dev/types/monitor_list_account_runs_response.py b/src/context/dev/types/monitor_list_account_runs_response.py index d148fac..0169354 100644 --- a/src/context/dev/types/monitor_list_account_runs_response.py +++ b/src/context/dev/types/monitor_list_account_runs_response.py @@ -5,8 +5,9 @@ from typing_extensions import Literal from .._models import BaseModel +from .webhook_delivery import WebhookDelivery -__all__ = ["MonitorListAccountRunsResponse", "Data", "DataError", "DataWebhookDelivery", "DataWebhookDeliveryError"] +__all__ = ["MonitorListAccountRunsResponse", "Data", "DataError"] class DataError(BaseModel): @@ -15,40 +16,6 @@ class DataError(BaseModel): message: str -class DataWebhookDeliveryError(BaseModel): - code: str - - message: str - - -class DataWebhookDelivery(BaseModel): - """The webhook delivery attempted for a change detected by this run. - - Omitted when no webhook was attempted, including historical runs created before delivery tracking was added. - """ - - attempted_at: datetime - - error: Optional[DataWebhookDeliveryError] = None - - event_id: str - """Identifier sent in the X-Context-Id header.""" - - http_status: Optional[int] = None - """ - The endpoint's final HTTP response status, or null when no response was - received. - """ - - status: Literal["delivered", "rejected", "failed", "skipped_unsafe_url"] - """Delivery outcome. - - delivered means any 2xx response; rejected means a non-2xx response; failed - means no HTTP response was received; skipped_unsafe_url means the URL failed the - public-endpoint safety check. - """ - - class Data(BaseModel): id: str @@ -90,11 +57,18 @@ class Data(BaseModel): started_at: Optional[datetime] = None - webhook_delivery: Optional[DataWebhookDelivery] = None - """The webhook delivery attempted for a change detected by this run. + webhook_deliveries: Optional[List[WebhookDelivery]] = None + """ + All webhook deliveries attempted by this run — one per subscribed event that + fired. Omitted when no webhook was attempted, including runs created before + event selection was added. + """ - Omitted when no webhook was attempted, including historical runs created before - delivery tracking was added. + webhook_delivery: Optional[WebhookDelivery] = None + """ + Deprecated: use `webhook_deliveries`, which records every attempt now that a run + can deliver multiple events. Omitted when no webhook was attempted, including + historical runs created before delivery tracking was added. """ diff --git a/src/context/dev/types/monitor_list_response.py b/src/context/dev/types/monitor_list_response.py index 9a5ae5b..a4af010 100644 --- a/src/context/dev/types/monitor_list_response.py +++ b/src/context/dev/types/monitor_list_response.py @@ -26,6 +26,7 @@ "DataBaselineMonitorsExtractBaseline", "DataLastError", "DataWebhook", + "DataWebhookFailure", ] @@ -209,7 +210,15 @@ class DataLastError(BaseModel): class DataWebhook(BaseModel): url: str - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: Optional[List[Literal["change.detected", "run.completed"]]] = None + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ secret: Optional[str] = None """Signing secret used to verify webhook authenticity. @@ -221,6 +230,27 @@ class DataWebhook(BaseModel): """ +class DataWebhookFailure(BaseModel): + """ + Present while webhook deliveries are failing consecutively; null when deliveries are healthy or no webhook is configured. Cleared on the next successful delivery and when the webhook URL changes. + """ + + consecutive_failures: int + """Number of consecutive delivery attempts that did not succeed.""" + + last_failed_at: datetime + + last_message: str + """Human-readable description of the most recent failure.""" + + last_status: Literal["rejected", "failed", "skipped_unsafe_url"] + """Outcome of the most recent failed delivery. + + rejected means a non-2xx response; failed means no HTTP response was received; + skipped_unsafe_url means the URL failed the public-endpoint safety check. + """ + + class Data(BaseModel): """A web monitor. @@ -287,6 +317,13 @@ class Data(BaseModel): webhook: Optional[DataWebhook] = None + webhook_failure: Optional[DataWebhookFailure] = None + """ + Present while webhook deliveries are failing consecutively; null when deliveries + are healthy or no webhook is configured. Cleared on the next successful delivery + and when the webhook URL changes. + """ + class MonitorListResponse(BaseModel): data: List[Data] diff --git a/src/context/dev/types/monitor_list_runs_response.py b/src/context/dev/types/monitor_list_runs_response.py index 94763c3..8ebccf2 100644 --- a/src/context/dev/types/monitor_list_runs_response.py +++ b/src/context/dev/types/monitor_list_runs_response.py @@ -5,8 +5,9 @@ from typing_extensions import Literal from .._models import BaseModel +from .webhook_delivery import WebhookDelivery -__all__ = ["MonitorListRunsResponse", "Data", "DataError", "DataWebhookDelivery", "DataWebhookDeliveryError"] +__all__ = ["MonitorListRunsResponse", "Data", "DataError"] class DataError(BaseModel): @@ -15,40 +16,6 @@ class DataError(BaseModel): message: str -class DataWebhookDeliveryError(BaseModel): - code: str - - message: str - - -class DataWebhookDelivery(BaseModel): - """The webhook delivery attempted for a change detected by this run. - - Omitted when no webhook was attempted, including historical runs created before delivery tracking was added. - """ - - attempted_at: datetime - - error: Optional[DataWebhookDeliveryError] = None - - event_id: str - """Identifier sent in the X-Context-Id header.""" - - http_status: Optional[int] = None - """ - The endpoint's final HTTP response status, or null when no response was - received. - """ - - status: Literal["delivered", "rejected", "failed", "skipped_unsafe_url"] - """Delivery outcome. - - delivered means any 2xx response; rejected means a non-2xx response; failed - means no HTTP response was received; skipped_unsafe_url means the URL failed the - public-endpoint safety check. - """ - - class Data(BaseModel): id: str @@ -90,11 +57,18 @@ class Data(BaseModel): started_at: Optional[datetime] = None - webhook_delivery: Optional[DataWebhookDelivery] = None - """The webhook delivery attempted for a change detected by this run. + webhook_deliveries: Optional[List[WebhookDelivery]] = None + """ + All webhook deliveries attempted by this run — one per subscribed event that + fired. Omitted when no webhook was attempted, including runs created before + event selection was added. + """ - Omitted when no webhook was attempted, including historical runs created before - delivery tracking was added. + webhook_delivery: Optional[WebhookDelivery] = None + """ + Deprecated: use `webhook_deliveries`, which records every attempt now that a run + can deliver multiple events. Omitted when no webhook was attempted, including + historical runs created before delivery tracking was added. """ diff --git a/src/context/dev/types/monitor_retrieve_change_response.py b/src/context/dev/types/monitor_retrieve_change_response.py index 115fa37..3bef95e 100644 --- a/src/context/dev/types/monitor_retrieve_change_response.py +++ b/src/context/dev/types/monitor_retrieve_change_response.py @@ -23,7 +23,7 @@ class Evidence(BaseModel): class MonitorRetrieveChangeResponse(BaseModel): """A detected change. - `mode` is the constant `web`; `target_type` and `change_detection_type` describe the change, and which optional fields are present depends on them (page: `diff` + excerpts; sitemap: `added_urls`/`removed_urls`; semantic: `query`/`confidence`/`importance`/`evidence`/`matched_urls`). + `mode` is the constant `web`; `target_type` and `change_detection_type` describe the change, and which optional fields are present depends on them (page: `diff` + excerpts; sitemap: `added_urls`/`removed_urls`; semantic: `confidence`/`importance`/`evidence`/`matched_urls`). """ id: str @@ -46,6 +46,9 @@ class MonitorRetrieveChangeResponse(BaseModel): summary: str + tags: List[str] + """User-defined tags for grouping and filtering monitors and their changes.""" + target_type: Literal["page", "sitemap", "extract"] title: str @@ -79,6 +82,3 @@ class MonitorRetrieveChangeResponse(BaseModel): removed_urls: Optional[List[str]] = None """At most 500 URLs are included; the corresponding count field is always exact.""" - - tags: Optional[List[str]] = None - """User-defined tags for grouping and filtering monitors and their changes.""" diff --git a/src/context/dev/types/monitor_retrieve_response.py b/src/context/dev/types/monitor_retrieve_response.py index 6a790bd..a9a623c 100644 --- a/src/context/dev/types/monitor_retrieve_response.py +++ b/src/context/dev/types/monitor_retrieve_response.py @@ -25,6 +25,7 @@ "BaselineMonitorsExtractBaseline", "LastError", "Webhook", + "WebhookFailure", ] @@ -208,7 +209,15 @@ class LastError(BaseModel): class Webhook(BaseModel): url: str - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: Optional[List[Literal["change.detected", "run.completed"]]] = None + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ secret: Optional[str] = None """Signing secret used to verify webhook authenticity. @@ -220,6 +229,27 @@ class Webhook(BaseModel): """ +class WebhookFailure(BaseModel): + """ + Present while webhook deliveries are failing consecutively; null when deliveries are healthy or no webhook is configured. Cleared on the next successful delivery and when the webhook URL changes. + """ + + consecutive_failures: int + """Number of consecutive delivery attempts that did not succeed.""" + + last_failed_at: datetime + + last_message: str + """Human-readable description of the most recent failure.""" + + last_status: Literal["rejected", "failed", "skipped_unsafe_url"] + """Outcome of the most recent failed delivery. + + rejected means a non-2xx response; failed means no HTTP response was received; + skipped_unsafe_url means the URL failed the public-endpoint safety check. + """ + + class MonitorRetrieveResponse(BaseModel): """A web monitor. @@ -285,3 +315,10 @@ class MonitorRetrieveResponse(BaseModel): """User-defined tags for grouping and filtering monitors and their changes.""" webhook: Optional[Webhook] = None + + webhook_failure: Optional[WebhookFailure] = None + """ + Present while webhook deliveries are failing consecutively; null when deliveries + are healthy or no webhook is configured. Cleared on the next successful delivery + and when the webhook URL changes. + """ diff --git a/src/context/dev/types/monitor_update_params.py b/src/context/dev/types/monitor_update_params.py index fa48e24..d0cb7bd 100644 --- a/src/context/dev/types/monitor_update_params.py +++ b/src/context/dev/types/monitor_update_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Union, Optional +from typing import Dict, List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict from .._types import SequenceNotStr @@ -166,4 +166,12 @@ class Webhook(TypedDict, total=False): """Set to null to remove the webhook.""" url: Required[str] - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: List[Literal["change.detected", "run.completed"]] + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ diff --git a/src/context/dev/types/monitor_update_response.py b/src/context/dev/types/monitor_update_response.py index 6184533..4f6757c 100644 --- a/src/context/dev/types/monitor_update_response.py +++ b/src/context/dev/types/monitor_update_response.py @@ -25,6 +25,7 @@ "BaselineMonitorsExtractBaseline", "LastError", "Webhook", + "WebhookFailure", ] @@ -208,7 +209,15 @@ class LastError(BaseModel): class Webhook(BaseModel): url: str - """Webhook URL called when a change is detected.""" + """Webhook URL events are delivered to.""" + + events: Optional[List[Literal["change.detected", "run.completed"]]] = None + """Events delivered to this endpoint. + + `change.detected` fires only when a run detects a change; `run.completed` fires + on every completed run — including runs that detected no change — and embeds the + change when one was detected. Defaults to `["change.detected"]` when omitted. + """ secret: Optional[str] = None """Signing secret used to verify webhook authenticity. @@ -220,6 +229,27 @@ class Webhook(BaseModel): """ +class WebhookFailure(BaseModel): + """ + Present while webhook deliveries are failing consecutively; null when deliveries are healthy or no webhook is configured. Cleared on the next successful delivery and when the webhook URL changes. + """ + + consecutive_failures: int + """Number of consecutive delivery attempts that did not succeed.""" + + last_failed_at: datetime + + last_message: str + """Human-readable description of the most recent failure.""" + + last_status: Literal["rejected", "failed", "skipped_unsafe_url"] + """Outcome of the most recent failed delivery. + + rejected means a non-2xx response; failed means no HTTP response was received; + skipped_unsafe_url means the URL failed the public-endpoint safety check. + """ + + class MonitorUpdateResponse(BaseModel): """A web monitor. @@ -285,3 +315,10 @@ class MonitorUpdateResponse(BaseModel): """User-defined tags for grouping and filtering monitors and their changes.""" webhook: Optional[Webhook] = None + + webhook_failure: Optional[WebhookFailure] = None + """ + Present while webhook deliveries are failing consecutively; null when deliveries + are healthy or no webhook is configured. Cleared on the next successful delivery + and when the webhook URL changes. + """ diff --git a/src/context/dev/types/parse_handle_params.py b/src/context/dev/types/parse_handle_params.py new file mode 100644 index 0000000..78bd93a --- /dev/null +++ b/src/context/dev/types/parse_handle_params.py @@ -0,0 +1,59 @@ +# 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__ = ["ParseHandleParams"] + + +class ParseHandleParams(TypedDict, total=False): + base_url: Annotated[str, PropertyInfo(alias="baseUrl")] + """ + Optional HTTP(S) source document URL used to resolve relative links and image + references. Relative references remain relative when omitted. + """ + + extension: str + """ + Optional file extension hint, such as pdf, docx, xlsx, pptx, html, json, csv, + md, py, rtf, jpg, png, or txt. + """ + + filename: str + """Optional filename hint used to infer the extension when extension is omitted.""" + + include_images: Annotated[bool, PropertyInfo(alias="includeImages")] + """Include image references in Markdown output""" + + include_links: Annotated[bool, PropertyInfo(alias="includeLinks")] + """Preserve hyperlinks in Markdown output""" + + ocr: bool + """ + When true for PDF inputs, detect and OCR images embedded in the selected pages, + inserting recognized text at each image's position in page reading order while + preserving the PDF text layer. pdfStart/pdfEnd limit the inclusive page range. + This is separate from automatic scanned-PDF OCR fallback. + """ + + pdf_end: Annotated[int, PropertyInfo(alias="pdfEnd")] + """Last 1-based PDF page to parse. + + When omitted, parsing ends at the last page. Must be greater than or equal to + pdfStart when both are provided. + """ + + pdf_start: Annotated[int, PropertyInfo(alias="pdfStart")] + """First 1-based PDF page to parse. + + When omitted, parsing starts at the first page. + """ + + shorten_base64_images: Annotated[bool, PropertyInfo(alias="shortenBase64Images")] + """Shorten base64-encoded image data in the Markdown output""" + + use_main_content_only: Annotated[bool, PropertyInfo(alias="useMainContentOnly")] + """Extract only the main content from HTML-like inputs""" diff --git a/src/context/dev/types/parse_handle_response.py b/src/context/dev/types/parse_handle_response.py new file mode 100644 index 0000000..8372811 --- /dev/null +++ b/src/context/dev/types/parse_handle_response.py @@ -0,0 +1,81 @@ +# 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__ = ["ParseHandleResponse", "KeyMetadata"] + + +class KeyMetadata(BaseModel): + """Metadata about the API key used for the request. + + Included in every response whenever a valid API key is provided, even when the response status is not 200. + """ + + credits_consumed: int + """The number of credits consumed by this request.""" + + credits_remaining: int + """The number of credits remaining for your organization after this request.""" + + +class ParseHandleResponse(BaseModel): + markdown: str + """Input bytes converted to GitHub Flavored Markdown""" + + success: Literal[True] + """Indicates success""" + + type: Literal[ + "html", + "xml", + "json", + "jsonl", + "text", + "csv", + "tsv", + "markdown", + "yaml", + "python", + "java", + "javascript", + "php", + "shell", + "ruby", + "typescript", + "rtf", + "srt", + "css", + "scss", + "less", + "stylus", + "sass", + "svg", + "pdf", + "docx", + "doc", + "xlsx", + "xls", + "pptx", + "ppt", + "jpg", + "png", + "gif", + "bmp", + "tiff", + "webp", + "ppm", + "pbm", + "pgm", + "pnm", + ] + """Detected content type used for parsing""" + + key_metadata: Optional[KeyMetadata] = None + """Metadata about the API key used for the request. + + Included in every response whenever a valid API key is provided, even when the + response status is not 200. + """ diff --git a/src/context/dev/types/web_web_crawl_md_params.py b/src/context/dev/types/web_web_crawl_md_params.py index c2026e3..0a7adce 100644 --- a/src/context/dev/types/web_web_crawl_md_params.py +++ b/src/context/dev/types/web_web_crawl_md_params.py @@ -276,8 +276,8 @@ class WebWebCrawlMdParams(TypedDict, total=False): pdf: Pdf """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page - range. + Use start/end to limit text extraction and embedded-image detection/OCR to an + inclusive 1-based page range. """ settle_animations: Annotated[bool, PropertyInfo(alias="settleAnimations")] @@ -324,7 +324,7 @@ class WebWebCrawlMdParams(TypedDict, total=False): class Pdf(TypedDict, total=False): """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + Use start/end to limit text extraction and embedded-image detection/OCR to an inclusive 1-based page range. """ end: int @@ -334,6 +334,13 @@ class Pdf(TypedDict, total=False): start when both are provided. """ + ocr: bool + """ + When true, detect and OCR images embedded in the selected PDF pages, inserting + recognized text at each image's position in page reading order while preserving + the PDF text layer. This is separate from automatic scanned-PDF OCR fallback. + """ + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] """When true, PDF pages are fetched and parsed. diff --git a/src/context/dev/types/web_web_scrape_html_params.py b/src/context/dev/types/web_web_scrape_html_params.py index a7e04d1..ae419ee 100644 --- a/src/context/dev/types/web_web_scrape_html_params.py +++ b/src/context/dev/types/web_web_scrape_html_params.py @@ -261,8 +261,8 @@ class WebWebScrapeHTMLParams(TypedDict, total=False): pdf: Pdf """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page - range. + Use start/end to limit text extraction and embedded-image detection/OCR to an + inclusive 1-based page range. """ settle_animations: Annotated[bool, PropertyInfo(alias="settleAnimations")] @@ -295,7 +295,7 @@ class WebWebScrapeHTMLParams(TypedDict, total=False): class Pdf(TypedDict, total=False): """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + Use start/end to limit text extraction and embedded-image detection/OCR to an inclusive 1-based page range. """ end: int @@ -305,6 +305,13 @@ class Pdf(TypedDict, total=False): start when both are provided. """ + ocr: bool + """ + When true, detect and OCR images embedded in the selected PDF pages, inserting + recognized text at each image's position in page reading order while preserving + the PDF text layer. This is separate from automatic scanned-PDF OCR fallback. + """ + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] """When true, PDF URLs are fetched and parsed. diff --git a/src/context/dev/types/web_web_scrape_md_params.py b/src/context/dev/types/web_web_scrape_md_params.py index 32ad153..89b6156 100644 --- a/src/context/dev/types/web_web_scrape_md_params.py +++ b/src/context/dev/types/web_web_scrape_md_params.py @@ -270,8 +270,8 @@ class WebWebScrapeMdParams(TypedDict, total=False): pdf: Pdf """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page - range. + Use start/end to limit text extraction and embedded-image detection/OCR to an + inclusive 1-based page range. """ settle_animations: Annotated[bool, PropertyInfo(alias="settleAnimations")] @@ -307,7 +307,7 @@ class WebWebScrapeMdParams(TypedDict, total=False): class Pdf(TypedDict, total=False): """PDF parsing controls. - Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + Use start/end to limit text extraction and embedded-image detection/OCR to an inclusive 1-based page range. """ end: int @@ -317,6 +317,13 @@ class Pdf(TypedDict, total=False): start when both are provided. """ + ocr: bool + """ + When true, detect and OCR images embedded in the selected PDF pages, inserting + recognized text at each image's position in page reading order while preserving + the PDF text layer. This is separate from automatic scanned-PDF OCR fallback. + """ + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] """When true, PDF URLs are fetched and parsed. diff --git a/src/context/dev/types/web_web_scrape_md_response.py b/src/context/dev/types/web_web_scrape_md_response.py index 7b673f0..1005d9e 100644 --- a/src/context/dev/types/web_web_scrape_md_response.py +++ b/src/context/dev/types/web_web_scrape_md_response.py @@ -102,6 +102,13 @@ class KeyMetadata(BaseModel): class WebWebScrapeMdResponse(BaseModel): + content_length: int = FieldInfo(alias="contentLength") + """UTF-8 byte length of the returned Markdown. + + Use 0 to identify an empty result and compare small values against your + workload's minimum useful-content threshold. + """ + markdown: str """Page content converted to GitHub Flavored Markdown""" diff --git a/src/context/dev/types/webhook_delivery.py b/src/context/dev/types/webhook_delivery.py new file mode 100644 index 0000000..5ec27d9 --- /dev/null +++ b/src/context/dev/types/webhook_delivery.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["WebhookDelivery", "Error"] + + +class Error(BaseModel): + code: str + + message: str + + +class WebhookDelivery(BaseModel): + attempted_at: datetime + + error: Optional[Error] = None + + event: Literal["change.detected", "run.completed"] + """The event this delivery carried. + + Deliveries recorded before event selection existed report change.detected. + """ + + event_id: str + """Identifier sent in the X-Context-Id header.""" + + http_status: Optional[int] = None + """ + The endpoint's final HTTP response status, or null when no response was + received. + """ + + status: Literal["delivered", "rejected", "failed", "skipped_unsafe_url"] + """Delivery outcome. + + delivered means any 2xx response; rejected means a non-2xx response; failed + means no HTTP response was received; skipped_unsafe_url means the URL failed the + public-endpoint safety check. + """ diff --git a/tests/api_resources/test_monitors.py b/tests/api_resources/test_monitors.py index 19301c8..03a2b09 100644 --- a/tests/api_resources/test_monitors.py +++ b/tests/api_resources/test_monitors.py @@ -66,7 +66,10 @@ def test_method_create_with_all_params(self, client: ContextDev) -> None: }, mode="web", tags=["pricing", "competitor"], - webhook={"url": "https://example.com/webhook"}, + webhook={ + "url": "https://example.com/webhook", + "events": ["change.detected", "run.completed"], + }, ) assert_matches_type(MonitorCreateResponse, monitor, path=["response"]) @@ -185,7 +188,10 @@ def test_method_update_with_all_params(self, client: ContextDev) -> None: "url": "https://acme.com/pricing", "normalize_whitespace": True, }, - webhook={"url": "https://example.com/webhook"}, + webhook={ + "url": "https://example.com/webhook", + "events": ["change.detected", "run.completed"], + }, ) assert_matches_type(MonitorUpdateResponse, monitor, path=["response"]) @@ -625,7 +631,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncContextDev }, mode="web", tags=["pricing", "competitor"], - webhook={"url": "https://example.com/webhook"}, + webhook={ + "url": "https://example.com/webhook", + "events": ["change.detected", "run.completed"], + }, ) assert_matches_type(MonitorCreateResponse, monitor, path=["response"]) @@ -744,7 +753,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncContextDev "url": "https://acme.com/pricing", "normalize_whitespace": True, }, - webhook={"url": "https://example.com/webhook"}, + webhook={ + "url": "https://example.com/webhook", + "events": ["change.detected", "run.completed"], + }, ) assert_matches_type(MonitorUpdateResponse, monitor, path=["response"]) diff --git a/tests/api_resources/test_parse.py b/tests/api_resources/test_parse.py new file mode 100644 index 0000000..f496f1e --- /dev/null +++ b/tests/api_resources/test_parse.py @@ -0,0 +1,128 @@ +# 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 context.dev import ContextDev, AsyncContextDev +from tests.utils import assert_matches_type +from context.dev.types import ParseHandleResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestParse: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_handle(self, client: ContextDev) -> None: + parse = client.parse.handle( + body=b"Example data", + ) + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_handle_with_all_params(self, client: ContextDev) -> None: + parse = client.parse.handle( + body=b"Example data", + base_url="https://example.com", + extension="extension", + filename="filename", + include_images=True, + include_links=True, + ocr=True, + pdf_end=1, + pdf_start=1, + shorten_base64_images=True, + use_main_content_only=True, + ) + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_handle(self, client: ContextDev) -> None: + response = client.parse.with_raw_response.handle( + body=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + parse = response.parse() + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_handle(self, client: ContextDev) -> None: + with client.parse.with_streaming_response.handle( + body=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + parse = response.parse() + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncParse: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_handle(self, async_client: AsyncContextDev) -> None: + parse = await async_client.parse.handle( + body=b"Example data", + ) + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_handle_with_all_params(self, async_client: AsyncContextDev) -> None: + parse = await async_client.parse.handle( + body=b"Example data", + base_url="https://example.com", + extension="extension", + filename="filename", + include_images=True, + include_links=True, + ocr=True, + pdf_end=1, + pdf_start=1, + shorten_base64_images=True, + use_main_content_only=True, + ) + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_handle(self, async_client: AsyncContextDev) -> None: + response = await async_client.parse.with_raw_response.handle( + body=b"Example data", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + parse = await response.parse() + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_handle(self, async_client: AsyncContextDev) -> None: + async with async_client.parse.with_streaming_response.handle( + body=b"Example data", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + parse = await response.parse() + assert_matches_type(ParseHandleResponse, parse, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_web.py b/tests/api_resources/test_web.py index 7e473c5..20ec0c1 100644 --- a/tests/api_resources/test_web.py +++ b/tests/api_resources/test_web.py @@ -373,6 +373,7 @@ def test_method_web_crawl_md_with_all_params(self, client: ContextDev) -> None: max_pages=1, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, }, @@ -433,6 +434,7 @@ def test_method_web_scrape_html_with_all_params(self, client: ContextDev) -> Non max_age_ms=0, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, }, @@ -545,6 +547,7 @@ def test_method_web_scrape_md_with_all_params(self, client: ContextDev) -> None: max_age_ms=0, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, }, @@ -978,6 +981,7 @@ async def test_method_web_crawl_md_with_all_params(self, async_client: AsyncCont max_pages=1, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, }, @@ -1038,6 +1042,7 @@ async def test_method_web_scrape_html_with_all_params(self, async_client: AsyncC max_age_ms=0, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, }, @@ -1150,6 +1155,7 @@ async def test_method_web_scrape_md_with_all_params(self, async_client: AsyncCon max_age_ms=0, pdf={ "end": 1, + "ocr": True, "should_parse": True, "start": 1, },