diff --git a/README.md b/README.md
index 70a842c..1edc5ce 100644
--- a/README.md
+++ b/README.md
@@ -289,7 +289,7 @@ from landingai_ade import LandingAIADE
client = LandingAIADE()
-job = client.v2.parse_jobs.create(document=Path("path/to/large_file.pdf"), priority="priority")
+job = client.v2.parse_jobs.create(document=Path("path/to/large_file.pdf"), service_tier="priority")
print(job.job_id, job.status)
# Block until the job is terminal (raises JobWaitTimeoutError / JobFailedError on failure paths)
@@ -302,20 +302,6 @@ if done.result is not None:
`parse_jobs.create` and `extract_jobs.create` both return a normalized `Job` -- one shape shared by parse and extract jobs, even though their upstream envelopes differ. Use `job.raw` to reach any field not surfaced on the typed model.
-### Uploading a file for `markdown_ref`
-
-`client.v2.files.upload` stages bytes on the ADE data plane and returns a `file_ref` you can pass as `markdown_ref` to extract:
-
-```python
-from pathlib import Path
-from landingai_ade import LandingAIADE
-
-client = LandingAIADE()
-
-file_ref = client.v2.files.upload(file=Path("path/to/file.md"))
-result = client.v2.extract(schema={"type": "object", "properties": {}}, markdown_ref=file_ref)
-```
-
`client.v2.parse`, `client.v2.extract`, and their async counterparts also accept `save_to`, with the same auto-naming behavior as the V1 methods above.
The async client mirrors this entire surface: `AsyncLandingAIADE().v2.parse(...)`, `await client.v2.parse_jobs.wait(...)`, etc.
diff --git a/api.md b/api.md
index 633045a..cba73d4 100644
--- a/api.md
+++ b/api.md
@@ -108,11 +108,11 @@ Methods:
Blocks, polling `.get(job_id)` with exponential backoff, until the job reaches a terminal status. Raises `JobWaitTimeoutError` if `timeout` seconds elapse first, and `JobFailedError` if `raise_on_failure=True` and the terminal job carries an `error` (not simply every `failed`/`cancelled` status).
-- client.v2.extract(\*, schema, markdown=..., markdown_ref=..., markdown_url=..., model=..., strict=..., idempotency_key=..., save_to=...) -> V2ExtractResult
+- client.v2.extract(\*, schema, markdown=..., markdown_url=..., model=..., strict=..., save_to=...) -> V2ExtractResult
- Synchronous extract. `schema` accepts a pydantic `BaseModel` subclass, a `dict`, or a JSON-encoded string -- all are coerced to a JSON Schema object. Provide exactly one of `markdown`, `markdown_ref` (e.g. from `client.v2.files.upload`), or `markdown_url`. `strict=True` rejects schemas with unsupported fields (HTTP 422) instead of silently pruning them. Raises `V2SyncTimeoutError` on a 504; use `extract_jobs` for long-running documents.
+ Synchronous extract. `schema` accepts a pydantic `BaseModel` subclass, a `dict`, or a JSON-encoded string -- all are coerced to a JSON Schema object. Provide exactly one of `markdown` or `markdown_url`. `strict=True` rejects schemas with unsupported fields (HTTP 422) instead of silently pruning them. Raises `V2SyncTimeoutError` on a 504; use `extract_jobs` for long-running documents.
-- client.v2.extract_jobs.create(\*, schema, markdown=..., markdown_ref=..., markdown_url=..., model=..., strict=..., idempotency_key=..., service_tier=...) -> Job
+- client.v2.extract_jobs.create(\*, schema, markdown=..., markdown_url=..., model=..., strict=..., service_tier=...) -> Job
- client.v2.extract_jobs.get(job_id) -> Job
- client.v2.extract_jobs.list(\*, page=..., page_size=..., status=...) -> JobList[Job]
- client.v2.extract_jobs.wait(job_id, \*, timeout=600, poll_interval=None, raise_on_failure=False) -> Job
@@ -121,7 +121,7 @@ Methods:
- client.v2.files.upload(\*, file) -> str
- Stages a file's bytes on the ADE data plane and returns a `file_ref` string, which can be passed as `markdown_ref` to `client.v2.extract`/`client.v2.extract_jobs.create`. Served on the ADE host under `/v1/files` (not `/v2/...`). Raises `LandingAiadeError` if the response has no `file_ref`.
+ Stages a file's bytes on the ADE data plane and returns a `file_ref` string for use in job inputs. Served on the ADE host under `/v1/files` (not `/v2/...`). Raises `LandingAiadeError` if the response has no `file_ref`.
Notes:
diff --git a/src/landingai_ade/resources/v2/extract.py b/src/landingai_ade/resources/v2/extract.py
index 266bb1c..0261eec 100644
--- a/src/landingai_ade/resources/v2/extract.py
+++ b/src/landingai_ade/resources/v2/extract.py
@@ -25,18 +25,15 @@
def _build_extract_body(
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: object,
- markdown_ref: object,
markdown_url: object,
model: object,
strict: object,
- idempotency_key: object,
service_tier: object = omit,
) -> Dict[str, Any]:
provided = [
name
for name, value in (
("markdown", markdown),
- ("markdown_ref", markdown_ref),
("markdown_url", markdown_url),
)
if value is not omit and value is not None
@@ -44,17 +41,15 @@ def _build_extract_body(
if len(provided) != 1:
raise ValueError(
"extract requires exactly one markdown source: provide one of "
- "`markdown`, `markdown_ref`, or `markdown_url`"
+ "`markdown` or `markdown_url`"
+ (f" (received: {', '.join(provided)})" if provided else "")
+ "."
)
body: Dict[str, Any] = {"schema": coerce_schema_to_dict(schema)}
for key, value in (
("markdown", markdown),
- ("markdown_ref", markdown_ref),
("markdown_url", markdown_url),
("model", model),
- ("idempotency_key", idempotency_key),
("service_tier", service_tier),
):
if value is not omit and value is not None:
@@ -70,11 +65,9 @@ def run(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
save_to: str | Path | None = None,
# 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.
@@ -97,9 +90,6 @@ def run(
markdown: Markdown content to extract data from.
- markdown_ref: A reference (e.g. from a prior parse) to markdown content to
- extract data from.
-
markdown_url: The URL to the markdown file to extract data from.
model: The version of the model to use for extraction.
@@ -108,8 +98,6 @@ def run(
False, prune unsupported fields and continue. Sent as
`options.strict`.
- idempotency_key: An idempotency key for the request.
-
save_to: Optional output path. If a directory, auto-generates the filename
(e.g. {input_file}_extract_output.json, or extract_output.json when no
input filename is available). If a full path ending in .json, saves there
@@ -123,7 +111,7 @@ def run(
timeout: Override the client-level default timeout for this request, in seconds
"""
- body = _build_extract_body(schema, markdown, markdown_ref, markdown_url, model, strict, idempotency_key)
+ body = _build_extract_body(schema, markdown, markdown_url, model, strict)
try:
result = self._post(
self._v2_url("/v2/extract"),
@@ -150,11 +138,9 @@ async def run(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
save_to: str | Path | None = None,
# 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.
@@ -164,7 +150,7 @@ async def run(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> V2ExtractResult:
"""Async mirror of `ExtractResource.run`. See there for full documentation."""
- body = _build_extract_body(schema, markdown, markdown_ref, markdown_url, model, strict, idempotency_key)
+ body = _build_extract_body(schema, markdown, markdown_url, model, strict)
try:
result = await self._post(
self._v2_url("/v2/extract"),
@@ -191,11 +177,9 @@ def create(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
service_tier: Optional[Literal["standard", "priority"]] | 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.
@@ -217,9 +201,6 @@ def create(
markdown: Markdown content to extract data from.
- markdown_ref: A reference (e.g. from a prior parse) to markdown content to
- extract data from.
-
markdown_url: The URL to the markdown file to extract data from.
model: The version of the model to use for extraction.
@@ -228,8 +209,6 @@ def create(
False, prune unsupported fields and continue. Sent as
`options.strict`.
- idempotency_key: An idempotency key for the request.
-
service_tier: Service tier for the job: ``standard`` or ``priority``.
extra_headers: Send extra headers
@@ -240,9 +219,7 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- body = _build_extract_body(
- schema, markdown, markdown_ref, markdown_url, model, strict, idempotency_key, service_tier
- )
+ body = _build_extract_body(schema, markdown, markdown_url, model, strict, service_tier)
raw = self._post(
self._v2_url("/v2/extract/jobs"),
body=body,
@@ -341,11 +318,9 @@ async def create(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
service_tier: Optional[Literal["standard", "priority"]] | 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.
@@ -355,9 +330,7 @@ async def create(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Job:
"""Async mirror of `ExtractJobsResource.create`. See there for full documentation."""
- body = _build_extract_body(
- schema, markdown, markdown_ref, markdown_url, model, strict, idempotency_key, service_tier
- )
+ body = _build_extract_body(schema, markdown, markdown_url, model, strict, service_tier)
raw = await self._post(
self._v2_url("/v2/extract/jobs"),
body=body,
diff --git a/src/landingai_ade/resources/v2/files.py b/src/landingai_ade/resources/v2/files.py
index fd25d97..a88b566 100644
--- a/src/landingai_ade/resources/v2/files.py
+++ b/src/landingai_ade/resources/v2/files.py
@@ -27,7 +27,7 @@ def upload(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> str:
- """Stage bytes on the data plane; returns a `file_ref` for use as extract `markdown_ref`."""
+ """Stage bytes on the data plane; returns a `file_ref` for use in job inputs."""
body = deepcopy_with_paths({"file": file}, [["file"]])
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
@@ -55,7 +55,7 @@ async def upload(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> str:
- """Stage bytes on the data plane; returns a `file_ref` for use as extract `markdown_ref`."""
+ """Stage bytes on the data plane; returns a `file_ref` for use in job inputs."""
body = deepcopy_with_paths({"file": file}, [["file"]])
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
diff --git a/src/landingai_ade/resources/v2/v2.py b/src/landingai_ade/resources/v2/v2.py
index ee20a69..befa049 100644
--- a/src/landingai_ade/resources/v2/v2.py
+++ b/src/landingai_ade/resources/v2/v2.py
@@ -96,11 +96,9 @@ def extract(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
save_to: str | Path | None = None,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
@@ -113,11 +111,9 @@ def extract(
return self._extract.run(
schema=schema,
markdown=markdown,
- markdown_ref=markdown_ref,
markdown_url=markdown_url,
model=model,
strict=strict,
- idempotency_key=idempotency_key,
save_to=save_to,
extra_headers=extra_headers,
extra_query=extra_query,
@@ -194,11 +190,9 @@ async def extract(
*,
schema: Union[str, Mapping[str, object], Type[BaseModel]],
markdown: Optional[str] | Omit = omit,
- markdown_ref: Optional[str] | Omit = omit,
markdown_url: Optional[str] | Omit = omit,
model: Optional[str] | Omit = omit,
strict: Optional[bool] | Omit = omit,
- idempotency_key: Optional[str] | Omit = omit,
save_to: str | Path | None = None,
# 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.
@@ -211,11 +205,9 @@ async def extract(
return await self._extract.run(
schema=schema,
markdown=markdown,
- markdown_ref=markdown_ref,
markdown_url=markdown_url,
model=model,
strict=strict,
- idempotency_key=idempotency_key,
save_to=save_to,
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/tests/api_resources/v2/test_extract.py b/tests/api_resources/v2/test_extract.py
index 4af2da2..becaf09 100644
--- a/tests/api_resources/v2/test_extract.py
+++ b/tests/api_resources/v2/test_extract.py
@@ -31,12 +31,11 @@ def test_extract_sync_json_body_with_pydantic_schema() -> None:
route = respx.post("https://api.ade.landing.ai/v2/extract").mock(
return_value=httpx.Response(200, json=EXTRACT_BODY)
)
- result = client.v2.extract(schema=Invoice, markdown="# doc", idempotency_key="k1")
+ result = client.v2.extract(schema=Invoice, markdown="# doc")
assert isinstance(result, V2ExtractResult) and result.metadata.version == "extract-1"
req = json.loads(route.calls.last.request.content)
assert req["schema"]["type"] == "object" and "revenue" in req["schema"]["properties"]
assert req["markdown"] == "# doc"
- assert req["idempotency_key"] == "k1"
assert route.calls.last.request.headers["content-type"].startswith("application/json")
@@ -55,7 +54,7 @@ def test_extract_sync_strict_option() -> None:
@respx.mock
def test_extract_requires_a_markdown_source() -> None:
# api.md documents the contract: provide exactly one of markdown /
- # markdown_ref / markdown_url. Omitting all three used to send a sourceless
+ # markdown_url. Omitting both used to send a sourceless
# body and surface an opaque server 500; the SDK now fails fast client-side.
# No route is registered: @respx.mock keeps this hermetic, so a regression in
# the guard fails loudly on an unmocked request instead of hitting the network.