@okrapdf/runtime 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 OkraPDF
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # @okrapdf/runtime
2
2
 
3
- Upload a PDF, get an API. That URL has REST endpoints for pages, entities, search, AI completion, SQL queries, and analytics.
3
+ Upload a PDF, get an API. Pages, entities, search, AI completion, structured output all from one URL.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@okrapdf/runtime)](https://www.npmjs.com/package/@okrapdf/runtime)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
4
7
 
5
8
  ## Install
6
9
 
@@ -11,12 +14,11 @@ npm install @okrapdf/runtime
11
14
  ## Quick Start
12
15
 
13
16
  ```ts
14
- import { OkraPDF } from '@okrapdf/runtime';
15
- import { z } from 'zod';
17
+ import { OkraClient } from '@okrapdf/runtime';
16
18
 
17
- const okra = new OkraPDF({ apiKey: process.env.OKRA_API_KEY });
19
+ const okra = new OkraClient({ apiKey: process.env.OKRA_API_KEY });
18
20
 
19
- // Upload
21
+ // Upload and wait
20
22
  const doc = await okra.upload('./report.pdf');
21
23
  await okra.wait(doc.id);
22
24
 
@@ -24,9 +26,16 @@ await okra.wait(doc.id);
24
26
  const pages = await okra.pages(doc.id);
25
27
 
26
28
  // Ask questions
27
- const answer = await okra.ask(doc.id, 'What was Q3 revenue?');
29
+ const { answer } = await okra.generate(doc.id, 'What was Q3 revenue?');
30
+ ```
31
+
32
+ ## Structured Output
33
+
34
+ Pass a Zod schema, get typed data back.
35
+
36
+ ```ts
37
+ import { z } from 'zod';
28
38
 
29
- // Structured output — pass a Zod schema, get typed data
30
39
  const Invoice = z.object({
31
40
  vendor: z.string(),
32
41
  total: z.number(),
@@ -36,24 +45,144 @@ const Invoice = z.object({
36
45
  })),
37
46
  });
38
47
 
39
- const result = await okra.structuredOutput(doc.id, Invoice, {
40
- query: 'Extract invoice fields',
48
+ const result = await okra.generate(doc.id, 'Extract invoice fields', {
49
+ schema: Invoice,
41
50
  });
42
51
  console.log(result.data.vendor); // fully typed
43
52
  ```
44
53
 
54
+ ## OpenAI-Compatible Endpoint
55
+
56
+ Every document becomes an OpenAI-compatible model. Works with any AI SDK.
57
+
58
+ ```ts
59
+ import { createOpenAI } from '@ai-sdk/openai';
60
+ import { generateText, generateObject } from 'ai';
61
+
62
+ const provider = createOpenAI({
63
+ baseURL: okra.modelEndpoint(doc.id),
64
+ apiKey: 'okra_...',
65
+ });
66
+
67
+ // Vercel AI SDK
68
+ const { text } = await generateText({
69
+ model: provider('default'),
70
+ prompt: 'What was revenue?',
71
+ });
72
+
73
+ // Structured output
74
+ const { object } = await generateObject({
75
+ model: provider('default'),
76
+ schema: Invoice,
77
+ prompt: 'Extract invoice fields',
78
+ });
79
+ ```
80
+
81
+ Also works with OpenAI SDK directly:
82
+
83
+ ```ts
84
+ import OpenAI from 'openai';
85
+
86
+ const openai = new OpenAI({
87
+ baseURL: okra.modelEndpoint(doc.id),
88
+ apiKey: 'okra_...',
89
+ });
90
+
91
+ const chat = await openai.chat.completions.create({
92
+ model: 'default',
93
+ messages: [{ role: 'user', content: 'Summarize' }],
94
+ });
95
+ ```
96
+
97
+ ## Streaming
98
+
99
+ ```ts
100
+ for await (const event of okra.stream(doc.id, 'Summarize this document')) {
101
+ if (event.type === 'text_delta') process.stdout.write(event.text);
102
+ if (event.type === 'done') console.log('\nCost:', event.costUsd);
103
+ }
104
+ ```
105
+
106
+ ## Multi-Document
107
+
108
+ ```ts
109
+ // Fan-out query across multiple documents
110
+ const result = await okra.generate(
111
+ ['doc_a', 'doc_b', 'doc_c'],
112
+ 'Compare revenue across all filings',
113
+ );
114
+ ```
115
+
45
116
  ## URL Builder
46
117
 
47
- Cloudinary for documents — every property is a CDN-cacheable URL.
118
+ Cloudinary-style — every property is a URL.
48
119
 
49
120
  ```tsx
50
- import { okraPdf } from '@okrapdf/runtime';
121
+ import { doc } from '@okrapdf/runtime';
122
+
123
+ const d = doc('doc_7fK3x', { fileName: 'annual-report.pdf' });
124
+
125
+ <Image src={d.thumbnail.url()} alt="Report cover" />
126
+ <Image src={d.pages[3].image.url()} />
127
+ <a href={d.entities.tables[0].url({ format: 'csv' })}>Download CSV</a>
128
+ ```
51
129
 
52
- const doc = okraPdf('doc_7fK3x');
130
+ When `fileName` is provided, URLs become mime-explicit aliases:
131
+ `/.../annual-report_ab12cd.json`, `.../annual-report_ab12cd.png`, `.../annual-report_ab12cd.md`.
53
132
 
54
- <Image src={doc.thumbnail.url()} alt="Report cover" />
55
- <Image src={doc.pages[3].image.url()} />
56
- <a href={doc.entities.tables[0].url({ format: 'csv' })}>Download CSV</a>
133
+ ### Browser Usage (No Node Imports)
134
+
135
+ Use the URL-builder-only entrypoint in browser code:
136
+
137
+ ```ts
138
+ import { doc } from '@okrapdf/runtime/doc';
139
+ ```
140
+
141
+ Or use a CDN module/global:
142
+
143
+ ```html
144
+ <script type="module">
145
+ import { doc } from 'https://cdn.jsdelivr.net/npm/@okrapdf/runtime/dist/browser.js';
146
+ const d = doc('ocr-7fK3x');
147
+ console.log(d.pages[1].markdown.url());
148
+ </script>
149
+ ```
150
+
151
+ ```html
152
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@okrapdf/runtime/dist/browser.js"></script>
153
+ <script>
154
+ const d = window.OkraRuntime.doc('ocr-7fK3x');
155
+ console.log(d.thumbnail.url());
156
+ </script>
157
+ ```
158
+
159
+ ## Provider Transformations
160
+
161
+ Same document, different extraction providers — visible in the URL. Like Cloudinary's `/w_300/image.jpg`, OkraPDF uses `/t_{provider}/` to select the extraction source.
162
+
163
+ ```ts
164
+ import { doc } from '@okrapdf/runtime';
165
+
166
+ const d = doc('doc_7fK3x', { provider: 'llamaparse' });
167
+
168
+ d.pages[1].markdown.url()
169
+ // → /v1/documents/doc_7fK3x/t_llamaparse/pages/1/markdown
170
+
171
+ d.entities.tables.url({ format: 'csv' })
172
+ // → /v1/documents/doc_7fK3x/t_llamaparse/entities/tables?format=csv
173
+ ```
174
+
175
+ Compare providers side-by-side:
176
+
177
+ ```ts
178
+ const d = doc('doc_7fK3x');
179
+
180
+ // Same page, different providers, different output formats
181
+ d.pages[1].url() // default provider
182
+ d.url({ provider: 'googleocr', format: 'json' }) // Google DocAI → JSON blocks
183
+ d.url({ provider: 'llamaparse', format: 'markdown' }) // LlamaParse → markdown
184
+ d.url({ provider: 'unstructured', format: 'html' }) // Unstructured → HTML (canonical)
185
+ d.url({ provider: 'docling', format: 'markdown' }) // Docling → markdown
57
186
  ```
58
187
 
59
188
  ## Provider Abstraction
@@ -70,36 +199,59 @@ const okra = createOkra({
70
199
  });
71
200
  ```
72
201
 
73
- ## Agent Sandbox
202
+ ## curl Equivalents
74
203
 
75
- Scope tool access to specific documents:
204
+ ```bash
205
+ # Upload
206
+ curl -X POST https://api.okrapdf.com/document/my-doc/upload \
207
+ -H "Authorization: Bearer okra_..." \
208
+ -H "Content-Type: application/pdf" \
209
+ --data-binary @report.pdf
76
210
 
77
- ```ts
78
- const tools = okra.sandbox({
79
- docs: [doc1.id, doc2.id],
80
- capabilities: ['read', 'query'],
81
- });
211
+ # Status
212
+ curl https://api.okrapdf.com/document/my-doc/status \
213
+ -H "Authorization: Bearer okra_..."
214
+
215
+ # Pages
216
+ curl https://api.okrapdf.com/document/my-doc/pages \
217
+ -H "Authorization: Bearer okra_..."
82
218
 
83
- // MCP-compatible
84
- const mcpTools = tools.asMcp();
219
+ # Completion
220
+ curl -X POST https://api.okrapdf.com/document/my-doc/completion \
221
+ -H "Authorization: Bearer okra_..." \
222
+ -H "Content-Type: application/json" \
223
+ -d '{"prompt": "What was revenue?"}'
85
224
  ```
86
225
 
87
- ## Streaming Completion
226
+ ## Full API
88
227
 
89
- ```ts
90
- for await (const event of okra.complete(doc.id, 'Summarize this document')) {
91
- if (event.type === 'text_delta') process.stdout.write(event.text);
92
- if (event.type === 'done') console.log('\nCost:', event.costUsd);
93
- }
228
+ ```
229
+ upload(path | url | buffer) Upload a document
230
+ wait(id) Poll until extraction complete
231
+ status(id) Check processing status
232
+ pages(id) Get all pages as markdown
233
+ page(id, num) Get single page
234
+ entities(id, { type }) Get extracted entities (tables, figures, etc.)
235
+ query(id, sql) Run SQL against document SQLite
236
+ generate(id, prompt) AI Q&A (non-streaming)
237
+ generate(id, prompt, { schema }) Structured output with Zod/JSON schema
238
+ stream(id, prompt) Streaming completion
239
+ modelEndpoint(id) OpenAI-compatible base URL
240
+ publish(id) Make document publicly accessible
241
+ shareLink(id, options) Generate share link with permissions
242
+ deploy(ids) Create multi-document agent
94
243
  ```
95
244
 
96
245
  ## Self-Host
97
246
 
98
247
  ```ts
99
- // worker.ts
100
248
  import { handleRequest } from '@okrapdf/runtime/worker';
101
249
 
102
250
  export default { fetch: handleRequest(env) };
103
251
  ```
104
252
 
105
253
  Same SDK, same code. Only `baseUrl` changes.
254
+
255
+ ## License
256
+
257
+ MIT
@@ -0,0 +1,7 @@
1
+ import { doc } from './url.js';
2
+ export { doc };
3
+ declare const _default: {
4
+ doc: typeof doc;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAc/B,OAAO,EAAE,GAAG,EAAE,CAAC;;;;AACf,wBAAuB"}
@@ -0,0 +1,9 @@
1
+ import { doc } from './url.js';
2
+ const runtimeGlobal = globalThis;
3
+ runtimeGlobal.OkraRuntime = {
4
+ ...(runtimeGlobal.OkraRuntime || {}),
5
+ doc,
6
+ };
7
+ export { doc };
8
+ export default { doc };
9
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAQ/B,MAAM,aAAa,GAAG,UAAkC,CAAC;AACzD,aAAa,CAAC,WAAW,GAAG;IAC1B,GAAG,CAAC,aAAa,CAAC,WAAW,IAAI,EAAE,CAAC;IACpC,GAAG;CACJ,CAAC;AAEF,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,eAAe,EAAE,GAAG,EAAE,CAAC"}
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AskResult, CompletionEvent, CompletionOptions, DocumentStatus, EntitiesResponse, OkraOptions, Page, PublishResult, QueryResult, Sandbox, ShareLinkOptions, ShareLinkResult, SandboxOptions, StructuredOutputOptions, StructuredOutputResult, StructuredSchema, UploadOptions, UploadResult, WaitOptions, AnalyticsResult } from './types.js';
1
+ import type { CompletionEvent, CompletionOptions, DeployOptions, DeployResult, DocumentStatus, EntitiesResponse, GenerateOptions, GenerateResult, OkraOptions, Page, PublishResult, QueryResult, ShareLinkOptions, ShareLinkResult, StructuredSchema, UploadOptions, UploadResult, WaitOptions } from './types.js';
2
2
  export declare class OkraClient {
3
3
  private readonly baseUrl;
4
4
  private readonly apiKey?;
@@ -20,18 +20,18 @@ export declare class OkraClient {
20
20
  signal?: AbortSignal;
21
21
  }): Promise<EntitiesResponse>;
22
22
  query(documentId: string, sql: string, signal?: AbortSignal): Promise<QueryResult>;
23
- complete(documentId: string, query: string, options?: CompletionOptions): AsyncGenerator<CompletionEvent>;
24
- ask(documentId: string | string[], query: string, signal?: AbortSignal): Promise<AskResult>;
25
- structuredOutput<T>(documentId: string, schema: StructuredSchema<T>, options: StructuredOutputOptions): Promise<StructuredOutputResult<T>>;
26
- structuredOutput<T>(documentId: string[], schema: StructuredSchema<T>, options: StructuredOutputOptions): Promise<Array<StructuredOutputResult<T>>>;
27
- private structuredOutputSingle;
23
+ stream(documentId: string, query: string, options?: CompletionOptions): AsyncGenerator<CompletionEvent>;
24
+ generate(documentId: string | string[], query: string, options?: GenerateOptions & {
25
+ schema?: undefined;
26
+ }): Promise<GenerateResult>;
27
+ generate<T>(documentId: string | string[], query: string, options: GenerateOptions & {
28
+ schema: StructuredSchema<T>;
29
+ }): Promise<GenerateResult<T>>;
30
+ private generateStructured;
31
+ modelEndpoint(documentId: string): string;
28
32
  publish(documentId: string, signal?: AbortSignal): Promise<PublishResult>;
29
33
  shareLink(documentId: string, options?: ShareLinkOptions): Promise<ShareLinkResult>;
30
- analytics(documentId: string, options?: {
31
- period?: string;
32
- signal?: AbortSignal;
33
- }): Promise<AnalyticsResult>;
34
- sandbox(options: SandboxOptions): Sandbox;
34
+ deploy(documentIds: string[], options?: DeployOptions): Promise<DeployResult>;
35
35
  private authHeaders;
36
36
  private rawRequest;
37
37
  private requestJson;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -68,9 +68,13 @@ export class OkraClient {
68
68
  const path = `/document/${encodeURIComponent(documentId)}`;
69
69
  const visibility = options.visibility || 'private';
70
70
  if (typeof input === 'string' && isHttpUrl(input)) {
71
+ const urlHeaders = { 'Content-Type': 'application/json' };
72
+ if (options.vendorKeys) {
73
+ urlHeaders['X-Vendor-Keys'] = JSON.stringify(options.vendorKeys);
74
+ }
71
75
  const response = await this.requestJson(`${path}/upload-url`, {
72
76
  method: 'POST',
73
- headers: { 'Content-Type': 'application/json' },
77
+ headers: urlHeaders,
74
78
  body: JSON.stringify({
75
79
  url: input,
76
80
  capabilities: options.capabilities,
@@ -101,6 +105,9 @@ export class OkraClient {
101
105
  if (options.capabilities) {
102
106
  headers['X-Capabilities'] = JSON.stringify(options.capabilities);
103
107
  }
108
+ if (options.vendorKeys) {
109
+ headers['X-Vendor-Keys'] = JSON.stringify(options.vendorKeys);
110
+ }
104
111
  if (visibility === 'public') {
105
112
  headers['X-Visibility'] = 'public';
106
113
  }
@@ -130,9 +137,6 @@ export class OkraClient {
130
137
  }
131
138
  const current = await this.status(documentId, options.signal);
132
139
  if (COMPLETE_PHASES.has(current.phase)) {
133
- if (options.autoPublish) {
134
- await this.publish(documentId, options.signal);
135
- }
136
140
  return current;
137
141
  }
138
142
  if (TERMINAL_ERROR_PHASES.has(current.phase)) {
@@ -183,8 +187,8 @@ export class OkraClient {
183
187
  async query(documentId, sql, signal) {
184
188
  return this.requestJson(`/document/${encodeURIComponent(documentId)}/query?select=${encodeURIComponent(sql)}`, { method: 'GET', signal });
185
189
  }
186
- // ─── Completion (streaming) ──────────────────────────────────────────────
187
- async *complete(documentId, query, options) {
190
+ // ─── Stream (streaming completion) ────────────────────────────────────────
191
+ async *stream(documentId, query, options) {
188
192
  const response = await this.rawRequest(`/document/${encodeURIComponent(documentId)}/completion`, {
189
193
  method: 'POST',
190
194
  headers: { 'Content-Type': 'application/json' },
@@ -235,57 +239,66 @@ export class OkraClient {
235
239
  reader.releaseLock();
236
240
  }
237
241
  }
238
- // ─── Ask (non-streaming convenience) ─────────────────────────────────────
239
- async ask(documentId, query, signal) {
242
+ async generate(documentId, query, options) {
240
243
  if (Array.isArray(documentId)) {
241
244
  // Multi-doc: fan-out and synthesize
242
- const results = await Promise.all(documentId.map((id) => this.ask(id, query, signal)));
245
+ const results = await Promise.all(documentId.map((id) => this.generate(id, query, options)));
243
246
  return {
244
247
  answer: results.map((r) => r.answer).join('\n\n'),
245
248
  costUsd: results.reduce((sum, r) => sum + (r.costUsd ?? 0), 0),
246
249
  };
247
250
  }
248
- // Single doc: non-streaming completion
251
+ // Structured output path
252
+ if (options?.schema) {
253
+ return this.generateStructured(documentId, query, options);
254
+ }
255
+ // Plain Q&A: non-streaming completion
249
256
  const result = await this.requestJson(`/document/${encodeURIComponent(documentId)}/completion`, {
250
257
  method: 'POST',
251
258
  headers: { 'Content-Type': 'application/json' },
252
259
  body: JSON.stringify({ prompt: query }),
253
- signal,
260
+ signal: options?.signal,
254
261
  });
255
262
  return {
256
263
  answer: result.answer,
257
264
  costUsd: result.usage?.costUsd,
258
265
  };
259
266
  }
260
- async structuredOutput(documentId, schema, options) {
261
- if (Array.isArray(documentId)) {
262
- return Promise.all(documentId.map((id) => this.structuredOutputSingle(id, schema, options)));
263
- }
264
- return this.structuredOutputSingle(documentId, schema, options);
265
- }
266
- async structuredOutputSingle(documentId, schema, options) {
267
- if (!options?.query || options.query.trim() === '') {
268
- throw new OkraRuntimeError('INVALID_REQUEST', 'structuredOutput requires a non-empty query', 400);
267
+ async generateStructured(documentId, query, options) {
268
+ if (!query || query.trim() === '') {
269
+ throw new OkraRuntimeError('INVALID_REQUEST', 'generate with schema requires a non-empty query', 400);
269
270
  }
270
- const normalized = normalizeSchema(schema);
271
+ const normalized = normalizeSchema(options.schema);
271
272
  const body = await this.requestJson(`/document/${encodeURIComponent(documentId)}/structured-output`, {
272
273
  method: 'POST',
273
274
  headers: { 'Content-Type': 'application/json' },
274
275
  body: JSON.stringify({
275
- query: options.query,
276
+ query,
276
277
  schema: normalized.jsonSchema,
277
278
  ...(options.timeoutMs ? { timeoutMs: options.timeoutMs } : {}),
278
279
  }),
279
280
  signal: options.signal,
280
281
  });
282
+ let data;
281
283
  if (normalized.parser) {
282
284
  const parsed = normalized.parser.safeParse(body.data);
283
285
  if (!parsed.success) {
284
286
  throw new StructuredOutputError('SCHEMA_VALIDATION_FAILED', 'Client-side schema validation failed for structured output response', 422, parsed.error.issues);
285
287
  }
286
- return { data: parsed.data, meta: body.meta };
288
+ data = parsed.data;
287
289
  }
288
- return body;
290
+ else {
291
+ data = body.data;
292
+ }
293
+ return {
294
+ answer: '',
295
+ data,
296
+ meta: body.meta,
297
+ };
298
+ }
299
+ // ─── Model Endpoint ──────────────────────────────────────────────────────
300
+ modelEndpoint(documentId) {
301
+ return `${this.baseUrl}/v1/documents/${encodeURIComponent(documentId)}`;
289
302
  }
290
303
  // ─── Publish / Share ────────────────────────────────────────────────────
291
304
  async publish(documentId, signal) {
@@ -300,6 +313,7 @@ export class OkraClient {
300
313
  method: 'POST',
301
314
  headers: { 'Content-Type': 'application/json' },
302
315
  body: JSON.stringify({
316
+ role: options?.role,
303
317
  label: options?.label,
304
318
  expiresInMs: options?.expiresInMs,
305
319
  maxViews: options?.maxViews,
@@ -307,99 +321,18 @@ export class OkraClient {
307
321
  signal: options?.signal,
308
322
  });
309
323
  }
310
- // ─── Analytics ───────────────────────────────────────────────────────────
311
- async analytics(documentId, options) {
312
- const params = options?.period ? `?period=${encodeURIComponent(options.period)}` : '';
313
- return this.requestJson(`/document/${encodeURIComponent(documentId)}/analytics${params}`, { method: 'GET', signal: options?.signal });
314
- }
315
- // ─── Sandbox ─────────────────────────────────────────────────────────────
316
- sandbox(options) {
317
- const capabilities = options.capabilities || ['read', 'query'];
318
- const tools = [];
319
- if (capabilities.includes('read')) {
320
- tools.push({
321
- name: 'get_pages',
322
- description: `Read page content from documents: ${options.docs.join(', ')}`,
323
- parameters: {
324
- type: 'object',
325
- properties: {
326
- document_id: { type: 'string', enum: options.docs },
327
- page_number: { type: 'number' },
328
- },
329
- required: ['document_id'],
330
- },
331
- execute: async (args) => {
332
- const docId = args.document_id;
333
- if (!options.docs.includes(docId))
334
- throw new Error(`Document ${docId} not in sandbox scope`);
335
- if (args.page_number)
336
- return this.page(docId, args.page_number);
337
- return this.pages(docId);
338
- },
339
- });
340
- tools.push({
341
- name: 'get_entities',
342
- description: `Get extracted entities (tables, figures, etc.) from documents: ${options.docs.join(', ')}`,
343
- parameters: {
344
- type: 'object',
345
- properties: {
346
- document_id: { type: 'string', enum: options.docs },
347
- type: { type: 'string', enum: ['table', 'figure', 'footnote', 'summary', 'signature'] },
348
- },
349
- required: ['document_id'],
350
- },
351
- execute: async (args) => {
352
- const docId = args.document_id;
353
- if (!options.docs.includes(docId))
354
- throw new Error(`Document ${docId} not in sandbox scope`);
355
- return this.entities(docId, { type: args.type });
356
- },
357
- });
358
- }
359
- if (capabilities.includes('query')) {
360
- tools.push({
361
- name: 'query_sql',
362
- description: `Run read-only SQL queries against document data: ${options.docs.join(', ')}`,
363
- parameters: {
364
- type: 'object',
365
- properties: {
366
- document_id: { type: 'string', enum: options.docs },
367
- sql: { type: 'string' },
368
- },
369
- required: ['document_id', 'sql'],
370
- },
371
- execute: async (args) => {
372
- const docId = args.document_id;
373
- if (!options.docs.includes(docId))
374
- throw new Error(`Document ${docId} not in sandbox scope`);
375
- return this.query(docId, args.sql);
376
- },
377
- });
378
- }
379
- if (capabilities.includes('complete')) {
380
- tools.push({
381
- name: 'ask_document',
382
- description: `Ask a natural-language question about documents: ${options.docs.join(', ')}`,
383
- parameters: {
384
- type: 'object',
385
- properties: {
386
- document_id: { type: 'string', enum: options.docs },
387
- question: { type: 'string' },
388
- },
389
- required: ['document_id', 'question'],
390
- },
391
- execute: async (args) => {
392
- const docId = args.document_id;
393
- if (!options.docs.includes(docId))
394
- throw new Error(`Document ${docId} not in sandbox scope`);
395
- return this.ask(docId, args.question);
396
- },
397
- });
398
- }
399
- return {
400
- tools,
401
- asMcp: () => tools,
402
- };
324
+ // ─── Deploy (Multi-Doc Agent) ─────────────────────────────────────────────
325
+ async deploy(documentIds, options) {
326
+ return this.requestJson('/api/agents/deploy', {
327
+ method: 'POST',
328
+ headers: { 'Content-Type': 'application/json' },
329
+ body: JSON.stringify({
330
+ documentIds,
331
+ name: options?.name,
332
+ documents: options?.documents,
333
+ }),
334
+ signal: options?.signal,
335
+ });
403
336
  }
404
337
  // ─── Internal HTTP ───────────────────────────────────────────────────────
405
338
  authHeaders() {