@anyformat/sdk 1.10.0 → 1.12.0

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/README.md CHANGED
@@ -103,6 +103,33 @@ await workflow.uploadDocumentsToDataset([
103
103
  Both are also available off the client: `af.uploadToDataset(workflowId, files, opts)`
104
104
  and `af.uploadDocumentsToDataset(workflowId, documents)`.
105
105
 
106
+ ## Evals
107
+
108
+ An eval re-extracts the dataset, or a slice of it picked by dataset tags, on one
109
+ workflow version and grades it against ground truth. It is billed per document,
110
+ so pass an `idempotencyKey` and an explicit `versionId` to make a retry replay
111
+ the original eval:
112
+
113
+ ```ts
114
+ const q3 = (await af.listDatasetTags(workflowId)).filter((t) => t.name === "Q3 invoices").map((t) => t.id);
115
+ const current = (await af.listWorkflowVersions(workflowId, { limit: 1 })).items[0]!.version_id;
116
+ const { eval_id } = await af.launchEval(workflowId, {
117
+ versionId: current,
118
+ datasetTagIds: q3,
119
+ untagged: true, // also the documents with no tag
120
+ idempotencyKey: `eval-${new Date().toISOString().slice(0, 10)}`, // one eval per day
121
+ });
122
+
123
+ let detail = await af.getEval(workflowId, eval_id); // poll until status leaves "in_progress"
124
+ const accuracy = await af.getEvalAccuracy(workflowId, eval_id); // per field, document, tag
125
+ ```
126
+
127
+ `getEvalDocumentPacketFields` shows one document's extracted values beside its
128
+ ground truth. To compare versions, read the evals `listEvals` returns: each
129
+ carries its `version_id`. To compare tags, read `by_dataset_tag` in the eval's
130
+ accuracy. Accuracy rows name fields by `persistent_id`;
131
+ `getWorkflow(workflowId, { version })` gives the names.
132
+
106
133
  ## Idempotency keys
107
134
 
108
135
  Upload and run triggers accept an `Idempotency-Key` (Stripe convention) —
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ module.exports = __toCommonJS(index_exports);
52
52
  // package.json
53
53
  var package_default = {
54
54
  name: "@anyformat/sdk",
55
- version: "1.10.0",
55
+ version: "1.12.0",
56
56
  description: "TypeScript SDK for the AnyFormat API",
57
57
  license: "MIT",
58
58
  author: "Anyformat <info@anyformat.ai>",
@@ -1178,6 +1178,11 @@ var v3UpdateWorkflow = (options) => (options.client ?? client).patch({
1178
1178
  ...options.headers
1179
1179
  }
1180
1180
  });
1181
+ var v3ListDatasetTags = (options) => (options.client ?? client).get({
1182
+ security: [{ scheme: "bearer", type: "http" }],
1183
+ url: "/v3/workflows/{workflow_id}/dataset/tags/",
1184
+ ...options
1185
+ });
1181
1186
  var v3UploadToDataset = (options) => (options.client ?? client).post({
1182
1187
  ...formDataBodySerializer,
1183
1188
  security: [{ scheme: "bearer", type: "http" }],
@@ -1193,6 +1198,35 @@ var v3ListWorkflowDocumentPackets = (options) => (options.client ?? client).get(
1193
1198
  url: "/v3/workflows/{workflow_id}/document-packets/",
1194
1199
  ...options
1195
1200
  });
1201
+ var v3ListEvals = (options) => (options.client ?? client).get({
1202
+ security: [{ scheme: "bearer", type: "http" }],
1203
+ url: "/v3/workflows/{workflow_id}/evals/",
1204
+ ...options
1205
+ });
1206
+ var v3LaunchEval = (options) => (options.client ?? client).post({
1207
+ security: [{ scheme: "bearer", type: "http" }],
1208
+ url: "/v3/workflows/{workflow_id}/evals/",
1209
+ ...options,
1210
+ headers: {
1211
+ "Content-Type": "application/json",
1212
+ ...options.headers
1213
+ }
1214
+ });
1215
+ var v3GetEval = (options) => (options.client ?? client).get({
1216
+ security: [{ scheme: "bearer", type: "http" }],
1217
+ url: "/v3/workflows/{workflow_id}/evals/{eval_id}/",
1218
+ ...options
1219
+ });
1220
+ var v3GetEvalAccuracy = (options) => (options.client ?? client).get({
1221
+ security: [{ scheme: "bearer", type: "http" }],
1222
+ url: "/v3/workflows/{workflow_id}/evals/{eval_id}/accuracy/",
1223
+ ...options
1224
+ });
1225
+ var v3GetEvalDocumentPacketFields = (options) => (options.client ?? client).get({
1226
+ security: [{ scheme: "bearer", type: "http" }],
1227
+ url: "/v3/workflows/{workflow_id}/evals/{eval_id}/document-packets/{document_packet_id}/fields/",
1228
+ ...options
1229
+ });
1196
1230
  var v3ListWorkflowRuns = (options) => (options.client ?? client).get({
1197
1231
  security: [{ scheme: "bearer", type: "http" }],
1198
1232
  url: "/v3/workflows/{workflow_id}/runs/",
@@ -1227,6 +1261,11 @@ var v3UploadAndRunWorkflow = (options) => (options.client ?? client).post({
1227
1261
  ...options.headers
1228
1262
  }
1229
1263
  });
1264
+ var v3ListWorkflowVersions = (options) => (options.client ?? client).get({
1265
+ security: [{ scheme: "bearer", type: "http" }],
1266
+ url: "/v3/workflows/{workflow_id}/versions/",
1267
+ ...options
1268
+ });
1230
1269
 
1231
1270
  // src/run.ts
1232
1271
  function isTransientStatus(status) {
@@ -1665,9 +1704,16 @@ var Anyformat = class {
1665
1704
  nextCursor: res.data.next_cursor ?? null
1666
1705
  };
1667
1706
  }
1668
- /** Retrieve a workflow with its complete typed graph inline (round-trippable into `updateWorkflow`). */
1669
- async getWorkflow(workflowId) {
1670
- const res = await v3GetWorkflow({ client: this._client, path: { workflow_id: workflowId } });
1707
+ /**
1708
+ * Retrieve a workflow with its complete typed graph inline (round-trippable into `updateWorkflow`).
1709
+ * Pass a `version_id` as `version` to read that version instead of the current one.
1710
+ */
1711
+ async getWorkflow(workflowId, opts = {}) {
1712
+ const res = await v3GetWorkflow({
1713
+ client: this._client,
1714
+ path: { workflow_id: workflowId },
1715
+ ...opts.version ? { query: { version: opts.version } } : {}
1716
+ });
1671
1717
  if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1672
1718
  return res.data;
1673
1719
  }
@@ -1791,6 +1837,26 @@ var Anyformat = class {
1791
1837
  cursor = page.nextCursor;
1792
1838
  }
1793
1839
  }
1840
+ /** A workflow's versions, newest first; item 0 of the first page is the current version. */
1841
+ async listWorkflowVersions(workflowId, opts = {}) {
1842
+ const res = await v3ListWorkflowVersions({
1843
+ client: this._client,
1844
+ path: { workflow_id: workflowId },
1845
+ query: { limit: opts.limit, cursor: opts.cursor }
1846
+ });
1847
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1848
+ return { items: res.data.items, nextCursor: res.data.next_cursor ?? null };
1849
+ }
1850
+ /** Every version of a workflow, newest first, following `nextCursor` across pages. Lazy. */
1851
+ async *iterWorkflowVersions(workflowId, opts = {}) {
1852
+ let cursor;
1853
+ for (; ; ) {
1854
+ const page = await this.listWorkflowVersions(workflowId, { limit: opts.limit, cursor });
1855
+ yield* page.items;
1856
+ if (page.nextCursor === null) return;
1857
+ cursor = page.nextCursor;
1858
+ }
1859
+ }
1794
1860
  /** Retrieve one run: lifecycle status plus results inline once `processed`. */
1795
1861
  async getRun(runId) {
1796
1862
  const res = await v3GetRun({ client: this._client, path: { run_id: runId } });
@@ -1837,6 +1903,70 @@ var Anyformat = class {
1837
1903
  if (run.status === "cancelled") throw new ExtractionCancelledError(runId);
1838
1904
  return null;
1839
1905
  }
1906
+ /** A workflow's dataset tags, ordered by name; a tag's `id` is what `datasetTagIds` takes. */
1907
+ async listDatasetTags(workflowId) {
1908
+ const res = await v3ListDatasetTags({ client: this._client, path: { workflow_id: workflowId } });
1909
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1910
+ return res.data.items;
1911
+ }
1912
+ /**
1913
+ * Launch an eval: extract every dataset document on a version and grade it
1914
+ * against ground truth. Billed per document. Omit `versionId` for the current
1915
+ * version. `idempotencyKey` makes a retry return the original eval instead of
1916
+ * launching a second one. `datasetTagIds: []` without `untagged: true` throws.
1917
+ */
1918
+ async launchEval(workflowId, opts = {}) {
1919
+ if (opts.datasetTagIds?.length === 0 && !opts.untagged) {
1920
+ throw new AnyformatError(
1921
+ "launchEval() datasetTagIds: [] selects no document; omit datasetTagIds to evaluate the whole dataset, or pass untagged: true"
1922
+ );
1923
+ }
1924
+ const res = await v3LaunchEval({
1925
+ client: this._client,
1926
+ path: { workflow_id: workflowId },
1927
+ body: {
1928
+ ...opts.versionId ? { version_id: opts.versionId } : {},
1929
+ ...opts.datasetTagIds ? { dataset_tag_ids: opts.datasetTagIds } : {},
1930
+ ...opts.untagged ? { untagged: true } : {}
1931
+ },
1932
+ ...opts.idempotencyKey ? { headers: { "Idempotency-Key": opts.idempotencyKey } } : {}
1933
+ });
1934
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1935
+ return res.data;
1936
+ }
1937
+ /** One eval's headline; poll it until `status` leaves `in_progress`. */
1938
+ async getEval(workflowId, evalId) {
1939
+ const res = await v3GetEval({ client: this._client, path: { workflow_id: workflowId, eval_id: evalId } });
1940
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1941
+ return res.data;
1942
+ }
1943
+ async listEvals(workflowId, opts = {}) {
1944
+ const res = await v3ListEvals({
1945
+ client: this._client,
1946
+ path: { workflow_id: workflowId },
1947
+ query: { limit: opts.limit, cursor: opts.cursor }
1948
+ });
1949
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1950
+ return { items: res.data.items, nextCursor: res.data.next_cursor ?? null };
1951
+ }
1952
+ /** An eval's accuracy per field, per document and per dataset tag; partial while it runs. */
1953
+ async getEvalAccuracy(workflowId, evalId) {
1954
+ const res = await v3GetEvalAccuracy({
1955
+ client: this._client,
1956
+ path: { workflow_id: workflowId, eval_id: evalId }
1957
+ });
1958
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1959
+ return res.data;
1960
+ }
1961
+ /** One eval document's extracted values beside its ground truth. The id is the dataset copy's. */
1962
+ async getEvalDocumentPacketFields(workflowId, evalId, documentPacketId) {
1963
+ const res = await v3GetEvalDocumentPacketFields({
1964
+ client: this._client,
1965
+ path: { workflow_id: workflowId, eval_id: evalId, document_packet_id: documentPacketId }
1966
+ });
1967
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error, res.response?.headers);
1968
+ return res.data;
1969
+ }
1840
1970
  };
1841
1971
 
1842
1972
  // src/schema.ts