Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ dist-deno
dist-bundle
*.mcpb
oidc

# local env / secrets — never commit API keys
.env
.env.local
.env.*.local
130 changes: 114 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@

[![NPM version](<https://img.shields.io/npm/v/landingai-ade.svg?label=npm%20(stable)>)](https://npmjs.org/package/landingai-ade) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/landingai-ade)


**[Playground](https://va.landing.ai) · [Discord](https://discord.com/invite/RVcW3j9RgR) · [Blog](https://landing.ai/blog) · [Docs](https://docs.landing.ai)**

</div>


This library provides convenient access to the LandingAI ADE REST API from server-side TypeScript or JavaScript.

The REST API documentation can be found on [docs.landing.ai](https://docs.landing.ai/). The full API of this library can be found in [api.md](api.md).
Expand Down Expand Up @@ -49,7 +47,11 @@ const client = new LandingAIADE({
environment: 'eu', // defaults to 'production'
});

const response = await client.parse({ document: fs.createReadStream('path/to/file'), model: 'dpt-2-latest', saveTo: './output_folder' });
const response = await client.parse({
document: fs.createReadStream('path/to/file'),
model: 'dpt-2-latest',
saveTo: './output_folder',
});
// optional: saves as {input_file}_parse_output.json in the specified folder

console.log(response.chunks);
Expand Down Expand Up @@ -102,14 +104,14 @@ const schema = {
properties: {
name: {
type: 'string',
description: "Person's name"
description: "Person's name",
},
age: {
type: 'number',
description: "Person's age"
}
description: "Person's age",
},
},
required: ['name', 'age']
required: ['name', 'age'],
};

const client = new LandingAIADE({
Expand All @@ -118,14 +120,14 @@ const client = new LandingAIADE({

const response = await client.extract({
schema: JSON.stringify(schema),
markdown: fs.createReadStream('path/to/file.md')
markdown: fs.createReadStream('path/to/file.md'),
});
```

For advanced type-safe schemas with full TypeScript inference, see [Using Zod for Type-Safe Schemas](#using-zod-for-type-safe-schemas).


### Split

Split parsed documents into separate sections based on classification rules and identifiers.

```js
Expand Down Expand Up @@ -170,6 +172,100 @@ for (const split of splitResponse.splits) {
}
```

### V2 API (`client.v2`)

`client.v2` is a new, **additive** sub-client for LandingAI's next-generation ADE gateway. It does not change anything about the V1 usage above — `client.parse`, `client.extract`, `client.parseJobs`, etc. keep working exactly as documented. Use `client.v2.*` for the newer parse/extract surface.

The V2 gateway lives on its own host (`api.ade.[env].landing.ai`), separate from the V1 host (`api.va.[env].landing.ai`). Select the environment the same way as V1, via the `environment` argument or the `LANDINGAI_ADE_ENVIRONMENT` env var:

```ts
import LandingAIADE from 'landingai-ade';

const client = new LandingAIADE({
apikey: process.env['VISION_AGENT_API_KEY'],
// one of "production" (default), "eu", "staging", "dev"
// can also be set via the LANDINGAI_ADE_ENVIRONMENT env var instead of passing it here
environment: 'staging',
});
```

#### V2 Parse

Parse a document synchronously. Returns a `V2ParseResponse` (on a partial success the HTTP status is 206 and `metadata.failed_pages` lists the unparsed pages). A synchronous 504 surfaces as `V2SyncTimeoutError` — use `parseJobs` (below) for long-running documents.

```ts
import fs from 'fs';

const response = await client.v2.parse({
document: fs.createReadStream('path/to/file.pdf'),
});
console.log(response.markdown);
```

#### V2 Extract

Extract structured data from Markdown using a JSON schema. Provide exactly one of `markdown`, `markdown_ref` (from `client.v2.files.upload`), or `markdown_url`.

```ts
const response = await client.v2.extract({
schema: { type: 'object', properties: { title: { type: 'string' } } },
markdown: 'some markdown',
});
```

`schema` accepts a JSON-Schema object or a JSON-encoded string. For type-safe schemas, define them with Zod and pass `z.toJSONSchema(MySchema)` (see [Using Zod for Type-Safe Schemas](#using-zod-for-type-safe-schemas)).

#### Async jobs

`parseJobs` / `extractJobs` create jobs and return one unified `Job` shape regardless of the divergent upstream envelopes (the full envelope stays on `Job.raw`). `wait()` polls with backoff until the job is terminal:

<!-- prettier-ignore -->
```ts
const job = await client.v2.parseJobs.create({
document: fs.createReadStream('large.pdf'),
service_tier: 'priority',
});
const done = await client.v2.parseJobs.wait(job.job_id, { timeout: 600000, raiseOnFailure: true });
console.log(done.status, done.result);

// client.v2.extractJobs.{create,get,list,wait} mirror the same shape for extract jobs.
```

#### File staging

`client.v2.files.upload` stages bytes on the ADE data plane and returns a `file_ref` you can pass as `markdown_ref` to extract:

<!-- prettier-ignore -->
```ts
const fileRef = await client.v2.files.upload({ file: fs.createReadStream('doc.md') });
const result = await client.v2.extract({ schema: { type: 'object' }, markdown_ref: fileRef });
```

`client.v2.parse` and `client.v2.extract` also accept `saveTo`, with the same auto-naming behavior as the V1 methods above.

#### Workflows (`parse-extract`)

`client.v2.workflow` runs a prebuilt pipeline (Phase 1: `parse-extract`) in one call — parse a document, then extract against a schema. Reference documents by `document_url`, or upload with `files.upload` and pass the returned ref as `document_ref`:

<!-- prettier-ignore -->
```ts
const result = await client.v2.workflow({
inputs: { report: { document_url: 'https://example.com/report.pdf' } },
steps: [
{
name: 'parse-extract',
document: '$inputs.report',
schema: { type: 'object', properties: { revenue: { type: 'string' } } },
},
],
});
console.log(result.output['parse-extract']);

// Async: client.v2.workflowJobs.{create,get,list,wait} mirror the jobs shape above.
```

To send a local file instead of a URL, pass it as `inputs.<name>.document` (the SDK stages it as a multipart part), or upload it first with `files.upload` and pass the returned ref as `document_ref`.

### Request & Response types

This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
Expand Down Expand Up @@ -237,12 +333,14 @@ const InvoiceSchema = z.object({
name: z.string(),
address: z.string().optional(),
}),
items: z.array(z.object({
description: z.string(),
quantity: z.number().int().positive(),
unitPrice: z.number().positive(),
total: z.number().positive(),
})),
items: z.array(
z.object({
description: z.string(),
quantity: z.number().int().positive(),
unitPrice: z.number().positive(),
total: z.number().positive(),
}),
),
totalAmount: z.number().describe('Total amount due'),
});

Expand All @@ -265,7 +363,7 @@ const result = await client.extract({
// 5. The extraction is now typed as Invoice
const invoice: Invoice = result.extraction as Invoice;
console.log(invoice.invoiceNumber); // TypeScript knows this is a string
console.log(invoice.totalAmount); // TypeScript knows this is a number
console.log(invoice.totalAmount); // TypeScript knows this is a number
```

Note: Zod is optional. You can also pass JSON Schema strings directly to the `extract` endpoint if you prefer.
Expand Down
36 changes: 36 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,39 @@ Methods:
- <code title="post /v1/ade/parse/jobs">client.parseJobs.<a href="./src/resources/parse-jobs.ts">create</a>({ ...params }) -> ParseJobCreateResponse</code>
- <code title="get /v1/ade/parse/jobs">client.parseJobs.<a href="./src/resources/parse-jobs.ts">list</a>({ ...params }) -> ParseJobListResponse</code>
- <code title="get /v1/ade/parse/jobs/{job_id}">client.parseJobs.<a href="./src/resources/parse-jobs.ts">get</a>(jobID) -> ParseJobGetResponse</code>

# V2

The `client.v2` sub-client targets LandingAI's next-generation ADE gateway on its own host (`api.ade.[env].landing.ai`), separate from the V1 host (`api.va.[env].landing.ai`). It is **additive** — `client.v2.*` is a separate surface from the top-level `client.*` (V1) methods above, and using it does not change any V1 behavior.

`client.v2.parseJobs` and `client.v2.extractJobs` both return a single, unified <a href="./src/resources/v2/types.ts">`Job`</a> shape even though the underlying parse/extract job envelopes differ upstream — `Job.raw` retains the full original envelope as an escape hatch.

Types:

- <code><a href="./src/resources/v2/types.ts">Job</a></code>
- <code><a href="./src/resources/v2/types.ts">JobError</a></code>
- <code><a href="./src/resources/v2/types.ts">JobList</a></code>
- <code><a href="./src/resources/v2/types.ts">JobStatus</a></code>
- <code><a href="./src/resources/v2/types.ts">V2ParseResponse</a></code>
- <code><a href="./src/resources/v2/types.ts">V2ExtractResult</a></code>
- <code><a href="./src/resources/v2/types.ts">V2WorkflowResult</a></code>
- <code><a href="./src/resources/v2/types.ts">V2FileUploadResponse</a></code>

Methods:

- <code title="post /v2/parse">client.v2.<a href="./src/resources/v2/v2.ts">parse</a>({ ...params }) -> V2ParseResponse</code>
- <code title="post /v2/extract">client.v2.<a href="./src/resources/v2/v2.ts">extract</a>({ ...params }) -> V2ExtractResult</code>
- <code title="post /v2/parse/jobs">client.v2.parseJobs.<a href="./src/resources/v2/parse.ts">create</a>({ ...params }) -> Job</code>
- <code title="get /v2/parse/jobs/{job_id}">client.v2.parseJobs.<a href="./src/resources/v2/parse.ts">get</a>(jobID) -> Job</code>
- <code title="get /v2/parse/jobs">client.v2.parseJobs.<a href="./src/resources/v2/parse.ts">list</a>({ ...params }) -> JobList</code>
- <code>client.v2.parseJobs.<a href="./src/resources/v2/parse.ts">wait</a>(jobID, { ...options }) -> Job</code>
- <code title="post /v2/extract/jobs">client.v2.extractJobs.<a href="./src/resources/v2/extract.ts">create</a>({ ...params }) -> Job</code>
- <code title="get /v2/extract/jobs/{job_id}">client.v2.extractJobs.<a href="./src/resources/v2/extract.ts">get</a>(jobID) -> Job</code>
- <code title="get /v2/extract/jobs">client.v2.extractJobs.<a href="./src/resources/v2/extract.ts">list</a>({ ...params }) -> JobList</code>
- <code>client.v2.extractJobs.<a href="./src/resources/v2/extract.ts">wait</a>(jobID, { ...options }) -> Job</code>
- <code title="post /v1/files">client.v2.files.<a href="./src/resources/v2/files.ts">upload</a>({ file }) -> string</code>
- <code title="post /v2/workflow">client.v2.<a href="./src/resources/v2/v2.ts">workflow</a>({ ...params }) -> V2WorkflowResult</code>
- <code title="post /v2/workflow/jobs">client.v2.workflowJobs.<a href="./src/resources/v2/workflow.ts">create</a>({ ...params }) -> Job</code>
- <code title="get /v2/workflow/jobs/{job_id}">client.v2.workflowJobs.<a href="./src/resources/v2/workflow.ts">get</a>(jobID) -> Job</code>
- <code title="get /v2/workflow/jobs">client.v2.workflowJobs.<a href="./src/resources/v2/workflow.ts">list</a>({ ...params }) -> JobList</code>
- <code>client.v2.workflowJobs.<a href="./src/resources/v2/workflow.ts">wait</a>(jobID, { ...options }) -> Job</code>
Loading