From 3159495092a7800a01fe13b441ffab57618f81ea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 02:23:30 +0000 Subject: [PATCH 1/5] fix(client): add missing f-string prefix in file type error message --- src/context/dev/_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/dev/_files.py b/src/context/dev/_files.py index 0fdce17..76da9e0 100644 --- a/src/context/dev/_files.py +++ b/src/context/dev/_files.py @@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles elif is_sequence_t(files): files = [(key, await _async_transform_file(file)) for key, file in files] else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") return files From 93da64127f9de0af6154364d5a99b8a2b43534f8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 14:49:27 +0000 Subject: [PATCH 2/5] feat(api): manual updates --- .stats.yml | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8baafcf..76025ca 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-18e7692e180f911962f33787228afa2cf31f6c05ab23c6afb1ca4f82b108fba5.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-fbe2d24f3b2c3f46adc35ff5fe7f2585dcababa7d9b649bd6c48fcfdd6d700de.yml openapi_spec_hash: 865bd1e346267d1e33f8ca63963c6aa3 -config_hash: 70354330f92ce169beabc98696ebb9a3 +config_hash: ff13935d1231ad44cd3822ffe39904b4 diff --git a/README.md b/README.md index 1aa1c6f..01da0b3 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ It is generated with [Stainless](https://www.stainless.com/). Use the Context Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=context.dev-mcp&config=eyJuYW1lIjoiY29udGV4dC5kZXYtbWNwIiwidHJhbnNwb3J0IjoiaHR0cCIsInVybCI6Imh0dHBzOi8vY29udGV4dC1kZXYuc3RsbWNwLmNvbSIsImhlYWRlcnMiOnsieC1jb250ZXh0LWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22context.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fcontext-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-context-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D) +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=context-dev-mcp&config=eyJuYW1lIjoiY29udGV4dC1kZXYtbWNwIiwidHJhbnNwb3J0IjoiaHR0cCIsInVybCI6Imh0dHBzOi8vY29udGV4dC1kZXYuc3RsbWNwLmNvbSIsImhlYWRlcnMiOnsieC1jb250ZXh0LWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22context-dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fcontext-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-context-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D) > Note: You may need to set environment variables in your MCP client. From e3419e41b590900a86e7b69309e32b716a61c558 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 14:51:25 +0000 Subject: [PATCH 3/5] feat(api): api update --- .stats.yml | 4 +- src/context/dev/resources/web.py | 54 +++++++++---------- .../dev/types/web_web_crawl_md_params.py | 39 +++++++++++--- .../dev/types/web_web_crawl_md_response.py | 3 +- .../dev/types/web_web_scrape_html_params.py | 38 ++++++++++--- .../dev/types/web_web_scrape_md_params.py | 38 ++++++++++--- tests/api_resources/test_web.py | 36 ++++++++++--- 7 files changed, 155 insertions(+), 57 deletions(-) diff --git a/.stats.yml b/.stats.yml index 76025ca..19d31b5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-fbe2d24f3b2c3f46adc35ff5fe7f2585dcababa7d9b649bd6c48fcfdd6d700de.yml -openapi_spec_hash: 865bd1e346267d1e33f8ca63963c6aa3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-c4963b57c26ac1a89f0ce8e04a280ee3d68e82d3fb02205623db6a53787112bc.yml +openapi_spec_hash: e277a9c81fa4a02f838be17487555ead config_hash: ff13935d1231ad44cd3822ffe39904b4 diff --git a/src/context/dev/resources/web.py b/src/context/dev/resources/web.py index 92cabf5..1361fc8 100644 --- a/src/context/dev/resources/web.py +++ b/src/context/dev/resources/web.py @@ -271,7 +271,7 @@ def web_crawl_md( max_age_ms: int | Omit = omit, max_depth: int | Omit = omit, max_pages: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_crawl_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, timeout_ms: int | Omit = omit, url_regex: str | Omit = omit, @@ -310,9 +310,8 @@ def web_crawl_md( max_pages: Maximum number of pages to crawl. Hard cap: 500. - parse_pdf: When true (default), PDF pages are fetched and their text layer is extracted and - converted to Markdown alongside HTML pages. When false, PDF pages are skipped - entirely (not included in results and not counted as failures). + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. shorten_base64_images: Truncate base64-encoded image data in the Markdown output @@ -348,7 +347,7 @@ def web_crawl_md( "max_age_ms": max_age_ms, "max_depth": max_depth, "max_pages": max_pages, - "parse_pdf": parse_pdf, + "pdf": pdf, "shorten_base64_images": shorten_base64_images, "timeout_ms": timeout_ms, "url_regex": url_regex, @@ -369,7 +368,7 @@ def web_scrape_html( url: str, include_frames: bool | Omit = omit, max_age_ms: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_scrape_html_params.Pdf | Omit = omit, timeout_ms: int | Omit = omit, wait_for_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -391,9 +390,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. - parse_pdf: When true (default), PDF URLs are fetched and their text layer is extracted and - returned wrapped in …. When false, PDF URLs are skipped - and a 400 WEBSITE_ACCESS_ERROR is returned. + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed @@ -423,7 +421,7 @@ def web_scrape_html( "url": url, "include_frames": include_frames, "max_age_ms": max_age_ms, - "parse_pdf": parse_pdf, + "pdf": pdf, "timeout_ms": timeout_ms, "wait_for_ms": wait_for_ms, }, @@ -507,7 +505,7 @@ def web_scrape_md( include_images: bool | Omit = omit, include_links: bool | Omit = omit, max_age_ms: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_scrape_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, timeout_ms: int | Omit = omit, use_main_content_only: bool | Omit = omit, @@ -536,9 +534,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. - parse_pdf: When true (default), PDF URLs are fetched and their text layer is extracted and - converted to Markdown. When false, PDF URLs are skipped and a 400 - WEBSITE_ACCESS_ERROR is returned. + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. shorten_base64_images: Shorten base64-encoded image data in the Markdown output @@ -574,7 +571,7 @@ def web_scrape_md( "include_images": include_images, "include_links": include_links, "max_age_ms": max_age_ms, - "parse_pdf": parse_pdf, + "pdf": pdf, "shorten_base64_images": shorten_base64_images, "timeout_ms": timeout_ms, "use_main_content_only": use_main_content_only, @@ -877,7 +874,7 @@ async def web_crawl_md( max_age_ms: int | Omit = omit, max_depth: int | Omit = omit, max_pages: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_crawl_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, timeout_ms: int | Omit = omit, url_regex: str | Omit = omit, @@ -916,9 +913,8 @@ async def web_crawl_md( max_pages: Maximum number of pages to crawl. Hard cap: 500. - parse_pdf: When true (default), PDF pages are fetched and their text layer is extracted and - converted to Markdown alongside HTML pages. When false, PDF pages are skipped - entirely (not included in results and not counted as failures). + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. shorten_base64_images: Truncate base64-encoded image data in the Markdown output @@ -954,7 +950,7 @@ async def web_crawl_md( "max_age_ms": max_age_ms, "max_depth": max_depth, "max_pages": max_pages, - "parse_pdf": parse_pdf, + "pdf": pdf, "shorten_base64_images": shorten_base64_images, "timeout_ms": timeout_ms, "url_regex": url_regex, @@ -975,7 +971,7 @@ async def web_scrape_html( url: str, include_frames: bool | Omit = omit, max_age_ms: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_scrape_html_params.Pdf | Omit = omit, timeout_ms: int | Omit = omit, wait_for_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -997,9 +993,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. - parse_pdf: When true (default), PDF URLs are fetched and their text layer is extracted and - returned wrapped in …. When false, PDF URLs are skipped - and a 400 WEBSITE_ACCESS_ERROR is returned. + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed @@ -1029,7 +1024,7 @@ async def web_scrape_html( "url": url, "include_frames": include_frames, "max_age_ms": max_age_ms, - "parse_pdf": parse_pdf, + "pdf": pdf, "timeout_ms": timeout_ms, "wait_for_ms": wait_for_ms, }, @@ -1113,7 +1108,7 @@ async def web_scrape_md( include_images: bool | Omit = omit, include_links: bool | Omit = omit, max_age_ms: int | Omit = omit, - parse_pdf: bool | Omit = omit, + pdf: web_web_scrape_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, timeout_ms: int | Omit = omit, use_main_content_only: bool | Omit = omit, @@ -1142,9 +1137,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. - parse_pdf: When true (default), PDF URLs are fetched and their text layer is extracted and - converted to Markdown. When false, PDF URLs are skipped and a 400 - WEBSITE_ACCESS_ERROR is returned. + pdf: PDF parsing controls. Use start/end to limit text extraction and OCR to an + inclusive 1-based page range. shorten_base64_images: Shorten base64-encoded image data in the Markdown output @@ -1180,7 +1174,7 @@ async def web_scrape_md( "include_images": include_images, "include_links": include_links, "max_age_ms": max_age_ms, - "parse_pdf": parse_pdf, + "pdf": pdf, "shorten_base64_images": shorten_base64_images, "timeout_ms": timeout_ms, "use_main_content_only": use_main_content_only, 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 dfd4fec..5ad4817 100644 --- a/src/context/dev/types/web_web_crawl_md_params.py +++ b/src/context/dev/types/web_web_crawl_md_params.py @@ -6,7 +6,7 @@ from .._utils import PropertyInfo -__all__ = ["WebWebCrawlMdParams"] +__all__ = ["WebWebCrawlMdParams", "Pdf"] class WebWebCrawlMdParams(TypedDict, total=False): @@ -45,11 +45,11 @@ class WebWebCrawlMdParams(TypedDict, total=False): max_pages: Annotated[int, PropertyInfo(alias="maxPages")] """Maximum number of pages to crawl. Hard cap: 500.""" - parse_pdf: Annotated[bool, PropertyInfo(alias="parsePDF")] - """ - When true (default), PDF pages are fetched and their text layer is extracted and - converted to Markdown alongside HTML pages. When false, PDF pages are skipped - entirely (not included in results and not counted as failures). + pdf: Pdf + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page + range. """ shorten_base64_images: Annotated[bool, PropertyInfo(alias="shortenBase64Images")] @@ -76,3 +76,30 @@ class WebWebCrawlMdParams(TypedDict, total=False): Optional browser wait time in milliseconds after initial page load for each crawled page. Min: 0. Max: 30000 (30 seconds). """ + + +class Pdf(TypedDict, total=False): + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + """ + + end: int + """Last 1-based PDF page to parse. + + When omitted, parsing ends at the last page. Must be greater than or equal to + start when both are provided. + """ + + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] + """When true, PDF pages are fetched and parsed. + + When false, PDF pages are skipped entirely (not included in results and not + counted as failures). + """ + + start: int + """First 1-based PDF page to parse. + + When omitted, parsing starts at the first page. + """ diff --git a/src/context/dev/types/web_web_crawl_md_response.py b/src/context/dev/types/web_web_crawl_md_response.py index 9c6cda1..c43975e 100644 --- a/src/context/dev/types/web_web_crawl_md_response.py +++ b/src/context/dev/types/web_web_crawl_md_response.py @@ -18,7 +18,8 @@ class Metadata(BaseModel): num_skipped: int = FieldInfo(alias="numSkipped") """ - Number of URLs skipped (PDFs when parsePDF=false, or URLs not matching urlRegex) + Number of URLs skipped (PDFs when pdf.shouldParse=false, or URLs not matching + urlRegex) """ num_succeeded: int = FieldInfo(alias="numSucceeded") 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 8f04cd3..7b39237 100644 --- a/src/context/dev/types/web_web_scrape_html_params.py +++ b/src/context/dev/types/web_web_scrape_html_params.py @@ -6,7 +6,7 @@ from .._utils import PropertyInfo -__all__ = ["WebWebScrapeHTMLParams"] +__all__ = ["WebWebScrapeHTMLParams", "Pdf"] class WebWebScrapeHTMLParams(TypedDict, total=False): @@ -23,11 +23,11 @@ class WebWebScrapeHTMLParams(TypedDict, total=False): omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. """ - parse_pdf: Annotated[bool, PropertyInfo(alias="parsePDF")] - """ - When true (default), PDF URLs are fetched and their text layer is extracted and - returned wrapped in …. When false, PDF URLs are skipped - and a 400 WEBSITE_ACCESS_ERROR is returned. + pdf: Pdf + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page + range. """ timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")] @@ -42,3 +42,29 @@ class WebWebScrapeHTMLParams(TypedDict, total=False): Min: 0. Max: 30000 (30 seconds). """ + + +class Pdf(TypedDict, total=False): + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + """ + + end: int + """Last 1-based PDF page to parse. + + When omitted, parsing ends at the last page. Must be greater than or equal to + start when both are provided. + """ + + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] + """When true, PDF URLs are fetched and parsed. + + When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned. + """ + + start: int + """First 1-based PDF page to parse. + + When omitted, parsing starts at the first page. + """ 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 0908d6c..fa06876 100644 --- a/src/context/dev/types/web_web_scrape_md_params.py +++ b/src/context/dev/types/web_web_scrape_md_params.py @@ -6,7 +6,7 @@ from .._utils import PropertyInfo -__all__ = ["WebWebScrapeMdParams"] +__all__ = ["WebWebScrapeMdParams", "Pdf"] class WebWebScrapeMdParams(TypedDict, total=False): @@ -32,11 +32,11 @@ class WebWebScrapeMdParams(TypedDict, total=False): omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. """ - parse_pdf: Annotated[bool, PropertyInfo(alias="parsePDF")] - """ - When true (default), PDF URLs are fetched and their text layer is extracted and - converted to Markdown. When false, PDF URLs are skipped and a 400 - WEBSITE_ACCESS_ERROR is returned. + pdf: Pdf + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page + range. """ shorten_base64_images: Annotated[bool, PropertyInfo(alias="shortenBase64Images")] @@ -60,3 +60,29 @@ class WebWebScrapeMdParams(TypedDict, total=False): Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). """ + + +class Pdf(TypedDict, total=False): + """PDF parsing controls. + + Use start/end to limit text extraction and OCR to an inclusive 1-based page range. + """ + + end: int + """Last 1-based PDF page to parse. + + When omitted, parsing ends at the last page. Must be greater than or equal to + start when both are provided. + """ + + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] + """When true, PDF URLs are fetched and parsed. + + When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned. + """ + + start: int + """First 1-based PDF page to parse. + + When omitted, parsing starts at the first page. + """ diff --git a/tests/api_resources/test_web.py b/tests/api_resources/test_web.py index 933c939..5839234 100644 --- a/tests/api_resources/test_web.py +++ b/tests/api_resources/test_web.py @@ -168,7 +168,11 @@ def test_method_web_crawl_md_with_all_params(self, client: ContextDev) -> None: max_age_ms=0, max_depth=0, max_pages=1, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, shorten_base64_images=True, timeout_ms=1000, url_regex="^https?://[^/]+/blog/", @@ -218,7 +222,11 @@ def test_method_web_scrape_html_with_all_params(self, client: ContextDev) -> Non url="https://example.com", include_frames=True, max_age_ms=0, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, timeout_ms=1000, wait_for_ms=0, ) @@ -318,7 +326,11 @@ def test_method_web_scrape_md_with_all_params(self, client: ContextDev) -> None: include_images=True, include_links=True, max_age_ms=0, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, shorten_base64_images=True, timeout_ms=1000, use_main_content_only=True, @@ -545,7 +557,11 @@ async def test_method_web_crawl_md_with_all_params(self, async_client: AsyncCont max_age_ms=0, max_depth=0, max_pages=1, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, shorten_base64_images=True, timeout_ms=1000, url_regex="^https?://[^/]+/blog/", @@ -595,7 +611,11 @@ async def test_method_web_scrape_html_with_all_params(self, async_client: AsyncC url="https://example.com", include_frames=True, max_age_ms=0, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, timeout_ms=1000, wait_for_ms=0, ) @@ -695,7 +715,11 @@ async def test_method_web_scrape_md_with_all_params(self, async_client: AsyncCon include_images=True, include_links=True, max_age_ms=0, - parse_pdf=True, + pdf={ + "end": 1, + "should_parse": True, + "start": 1, + }, shorten_base64_images=True, timeout_ms=1000, use_main_content_only=True, From 23cc0fbc81f823fb5da255c58b2f493fbcd0be68 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 16:05:48 +0000 Subject: [PATCH 4/5] feat(api): api update --- .stats.yml | 4 ++-- src/context/dev/resources/web.py | 14 ++++++++++++++ src/context/dev/types/web_web_crawl_md_params.py | 8 ++++++++ tests/api_resources/test_web.py | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 19d31b5..ddc345a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-c4963b57c26ac1a89f0ce8e04a280ee3d68e82d3fb02205623db6a53787112bc.yml -openapi_spec_hash: e277a9c81fa4a02f838be17487555ead +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-f27c9584f74632a8c9603fce7190e3f63275a4ec4030da2a9475efb619618b3f.yml +openapi_spec_hash: 224cb935536a4d999d9683f8c03ea32f config_hash: ff13935d1231ad44cd3822ffe39904b4 diff --git a/src/context/dev/resources/web.py b/src/context/dev/resources/web.py index 1361fc8..f98ed51 100644 --- a/src/context/dev/resources/web.py +++ b/src/context/dev/resources/web.py @@ -273,6 +273,7 @@ def web_crawl_md( max_pages: int | Omit = omit, pdf: web_web_crawl_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, + stop_after_ms: int | Omit = omit, timeout_ms: int | Omit = omit, url_regex: str | Omit = omit, use_main_content_only: bool | Omit = omit, @@ -315,6 +316,11 @@ def web_crawl_md( shorten_base64_images: Truncate base64-encoded image data in the Markdown output + stop_after_ms: Soft time budget for the crawl in milliseconds. After each scrape, the crawler + checks the elapsed time and, if exceeded, returns the pages collected so far + instead of continuing. Min: 10000 (10s). Max: 240000 (4 min). Default: 120000 (2 + min). + timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes). @@ -349,6 +355,7 @@ def web_crawl_md( "max_pages": max_pages, "pdf": pdf, "shorten_base64_images": shorten_base64_images, + "stop_after_ms": stop_after_ms, "timeout_ms": timeout_ms, "url_regex": url_regex, "use_main_content_only": use_main_content_only, @@ -876,6 +883,7 @@ async def web_crawl_md( max_pages: int | Omit = omit, pdf: web_web_crawl_md_params.Pdf | Omit = omit, shorten_base64_images: bool | Omit = omit, + stop_after_ms: int | Omit = omit, timeout_ms: int | Omit = omit, url_regex: str | Omit = omit, use_main_content_only: bool | Omit = omit, @@ -918,6 +926,11 @@ async def web_crawl_md( shorten_base64_images: Truncate base64-encoded image data in the Markdown output + stop_after_ms: Soft time budget for the crawl in milliseconds. After each scrape, the crawler + checks the elapsed time and, if exceeded, returns the pages collected so far + instead of continuing. Min: 10000 (10s). Max: 240000 (4 min). Default: 120000 (2 + min). + timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes). @@ -952,6 +965,7 @@ async def web_crawl_md( "max_pages": max_pages, "pdf": pdf, "shorten_base64_images": shorten_base64_images, + "stop_after_ms": stop_after_ms, "timeout_ms": timeout_ms, "url_regex": url_regex, "use_main_content_only": use_main_content_only, 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 5ad4817..03539b2 100644 --- a/src/context/dev/types/web_web_crawl_md_params.py +++ b/src/context/dev/types/web_web_crawl_md_params.py @@ -55,6 +55,14 @@ class WebWebCrawlMdParams(TypedDict, total=False): shorten_base64_images: Annotated[bool, PropertyInfo(alias="shortenBase64Images")] """Truncate base64-encoded image data in the Markdown output""" + stop_after_ms: Annotated[int, PropertyInfo(alias="stopAfterMs")] + """Soft time budget for the crawl in milliseconds. + + After each scrape, the crawler checks the elapsed time and, if exceeded, returns + the pages collected so far instead of continuing. Min: 10000 (10s). Max: 240000 + (4 min). Default: 120000 (2 min). + """ + timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")] """Optional timeout in milliseconds for the request. diff --git a/tests/api_resources/test_web.py b/tests/api_resources/test_web.py index 5839234..5c31c7f 100644 --- a/tests/api_resources/test_web.py +++ b/tests/api_resources/test_web.py @@ -174,6 +174,7 @@ def test_method_web_crawl_md_with_all_params(self, client: ContextDev) -> None: "start": 1, }, shorten_base64_images=True, + stop_after_ms=10000, timeout_ms=1000, url_regex="^https?://[^/]+/blog/", use_main_content_only=True, @@ -563,6 +564,7 @@ async def test_method_web_crawl_md_with_all_params(self, async_client: AsyncCont "start": 1, }, shorten_base64_images=True, + stop_after_ms=10000, timeout_ms=1000, url_regex="^https?://[^/]+/blog/", use_main_content_only=True, From 3e40dfb6e5be0732a1fd211c5c48cade941ebce3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 16:06:09 +0000 Subject: [PATCH 5/5] release: 0.20.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/context/dev/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e756293..0c2ecec 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.19.0" + ".": "0.20.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9a131..3a18db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.20.0 (2026-05-10) + +Full Changelog: [v0.19.0...v0.20.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.19.0...v0.20.0) + +### Features + +* **api:** api update ([23cc0fb](https://github.com/context-dot-dev/context-python-sdk/commit/23cc0fbc81f823fb5da255c58b2f493fbcd0be68)) +* **api:** api update ([e3419e4](https://github.com/context-dot-dev/context-python-sdk/commit/e3419e41b590900a86e7b69309e32b716a61c558)) +* **api:** manual updates ([93da641](https://github.com/context-dot-dev/context-python-sdk/commit/93da64127f9de0af6154364d5a99b8a2b43534f8)) + + +### Bug Fixes + +* **client:** add missing f-string prefix in file type error message ([3159495](https://github.com/context-dot-dev/context-python-sdk/commit/3159495092a7800a01fe13b441ffab57618f81ea)) + ## 0.19.0 (2026-05-09) Full Changelog: [v0.18.0...v0.19.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.18.0...v0.19.0) diff --git a/pyproject.toml b/pyproject.toml index 4bb887a..e15bab8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "context.dev" -version = "0.19.0" +version = "0.20.0" description = "The official Python library for the context.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/context/dev/_version.py b/src/context/dev/_version.py index 4028ca7..eccf38e 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__ = "0.19.0" # x-release-please-version +__version__ = "0.20.0" # x-release-please-version