@pipelex/sdk 0.52.0 → 0.53.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 +17 -17
- package/dist/answer-reading.d.ts +70 -0
- package/dist/answer-reading.js +106 -0
- package/dist/answer-reading.js.map +1 -0
- package/dist/artifacts.js +45 -32
- package/dist/artifacts.js.map +1 -1
- package/dist/cli/present.d.ts +11 -14
- package/dist/cli/present.js +41 -37
- package/dist/cli/present.js.map +1 -1
- package/dist/cli/run.js +8 -7
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/script.d.ts +1 -1
- package/dist/cli/source.js +2 -2
- package/dist/cli/source.js.map +1 -1
- package/dist/client.d.ts +248 -218
- package/dist/client.js +538 -477
- package/dist/client.js.map +1 -1
- package/dist/codegen-check.d.ts +21 -15
- package/dist/codegen-check.js +54 -27
- package/dist/codegen-check.js.map +1 -1
- package/dist/errors.d.ts +298 -455
- package/dist/errors.js +426 -534
- package/dist/errors.js.map +1 -1
- package/dist/exact-json.d.ts +8 -12
- package/dist/exact-json.js +19 -12
- package/dist/exact-json.js.map +1 -1
- package/dist/hooks/check-core.d.ts +12 -7
- package/dist/hooks/check-core.js +20 -14
- package/dist/hooks/check-core.js.map +1 -1
- package/dist/hooks/validate-stage.js +12 -3
- package/dist/hooks/validate-stage.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/method-selector.js +7 -5
- package/dist/method-selector.js.map +1 -1
- package/dist/method-trees.d.ts +6 -7
- package/dist/method-trees.js +31 -37
- package/dist/method-trees.js.map +1 -1
- package/dist/models.d.ts +33 -210
- package/dist/models.js +2 -1
- package/dist/models.js.map +1 -1
- package/dist/prepare-inputs.d.ts +2 -2
- package/dist/prepare-inputs.js +51 -54
- package/dist/prepare-inputs.js.map +1 -1
- package/dist/problem-items.d.ts +19 -0
- package/dist/problem-items.js +52 -0
- package/dist/problem-items.js.map +1 -0
- package/dist/product-models.d.ts +23 -21
- package/dist/records.d.ts +12 -0
- package/dist/records.js +23 -0
- package/dist/records.js.map +1 -0
- package/dist/runs.d.ts +49 -38
- package/dist/runs.js +45 -19
- package/dist/runs.js.map +1 -1
- package/dist/transport-reading.d.ts +18 -0
- package/dist/{run-may-have-started.js → transport-reading.js} +15 -44
- package/dist/transport-reading.js.map +1 -0
- package/dist/upload-grant.d.ts +9 -6
- package/dist/upload-grant.js +42 -29
- package/dist/upload-grant.js.map +1 -1
- package/dist/upload.js +53 -33
- package/dist/upload.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/architecture.md +19 -19
- package/docs/artifact-download.md +6 -6
- package/docs/cli.md +1 -1
- package/docs/crate-routes.md +13 -14
- package/docs/errors.md +154 -267
- package/docs/exact-integers.md +1 -1
- package/docs/files.md +13 -13
- package/docs/hook-bundle.md +15 -1
- package/docs/input-preparation.md +14 -14
- package/docs/method-copy.md +24 -24
- package/docs/method-examples.md +13 -14
- package/docs/method-trees.md +27 -28
- package/docs/organization-branding.md +14 -16
- package/docs/run-results.md +8 -8
- package/package.json +1 -1
- package/dist/error-models.d.ts +0 -302
- package/dist/error-models.js +0 -203
- package/dist/error-models.js.map +0 -1
- package/dist/error-verdicts.d.ts +0 -46
- package/dist/error-verdicts.js +0 -120
- package/dist/error-verdicts.js.map +0 -1
- package/dist/run-may-have-started.d.ts +0 -31
- package/dist/run-may-have-started.js.map +0 -1
package/docs/method-trees.md
CHANGED
|
@@ -33,7 +33,7 @@ const verdict = await client.validate({
|
|
|
33
33
|
|
|
34
34
|
**A directory is listed by the standard's lister.** The client loads the `mthds` package's `listMethodTree` when a call gives a `directory`, and lists it under the MTHDS standard's membership rule and Manifest Discovery: the tree is rooted at the nearest `METHODS.toml` at or above the directory, else at the directory itself, and holds every file the rule keeps. Hidden entries, `node_modules`, `__pycache__`, what a `.gitignore` or the manifest's `exclude` keeps out, and **a run's inputs file** (`inputs.json`, `inputs.toml`) never travel with the method. A tree holding a symbolic link or a special file is refused rather than followed. The directory is listed under the limits the deployment announces (below), so a tree the deployment would refuse for its size is refused while it is listed, before any file is hashed. Every refusal is a `RequestArgumentError` naming the call and the directory, whose `cause` is `mthds`'s `MethodTreeError`, with its `code` (`not_found`, `symbolic_link`, `limit_exceeded`, `empty_tree` and the rest). Listing needs Node: the lister comes from the Node host ([architecture.md](./architecture.md#the-node-host)), so a bundle built for the browser holds none of it, and a `directory` given outside Node is refused with `RequestArgumentError` before the version handshake, so before any request, and a browser gives `contents`, `tree` or `files`.
|
|
35
35
|
|
|
36
|
-
**A map in memory.** A text in `contents` is encoded in UTF-8, and a text a file cannot hold, one carrying a lone surrogate, is refused, as is a value that is neither a string nor a `Uint8Array`. The keys are sent as they are, and the platform refuses one that is not a tree path with
|
|
36
|
+
**A map in memory.** A text in `contents` is encoded in UTF-8, and a text a file cannot hold, one carrying a lone surrogate, is refused, as is a value that is neither a string nor a `Uint8Array`. The keys are sent as they are, and the platform refuses one that is not a tree path with a `422` `method.package_invalid` whose `params` name its `path`.
|
|
37
37
|
|
|
38
38
|
**One form, and never an empty tree.** Two forms at once are refused with a `RequestArgumentError` before anything is read or sent. A `files` map, `contents` or a `tree` holding no file is refused too on the run routes and on `validate`, as the standard refuses it: a tree holds at least one file. On the crate routes and in `prepareInputs`, an empty map is absent instead, so it never reaches the wire as a second selector, and in a save `files: null` empties the draft. An empty `directory` string is absent everywhere.
|
|
39
39
|
|
|
@@ -46,42 +46,41 @@ A tree given as a `directory`, `contents` or `tree` is sent by the rule the `mth
|
|
|
46
46
|
|
|
47
47
|
A `files` map is sent as given, with no handshake. A run's `start` carrying a tree, a run that names a `method_ref`, and a start whose `extra` carries a method bundle (`mthds_contents` or `bundle_b64`, as the `pipelex-sdk` command sends one) get the client's request ceiling rather than the 30-second start budget, since the body can be large. On the crate routes, a request whose `files` carry more than `INLINE_TREE_MAX_BYTES` inline, as a tree sent to an API keeping no blob store or a `files` map given as is may, gets the request ceiling too rather than the 30-second budget of a static route ([crate-routes.md](./crate-routes.md)). A save carrying a tree (`createMethod`, `writeDraft`), inline or by hash, gets the request ceiling as well, rather than the 30-second budget of a save sending none, since a tree sent inline to an API keeping no blob store can be large and its whole upload is charged against the budget.
|
|
48
48
|
|
|
49
|
-
**A refusal of the tree's size is sent once more.** When the API refuses a tree the client prepared, a `directory`, `contents` or `tree`, as past one of its limits (a `422`
|
|
49
|
+
**A refusal of the tree's size is sent once more.** When the API refuses a tree the client prepared, a `directory`, `contents` or `tree`, as past one of its limits (a `422` `method.package_invalid` whose `params` carry `reason` `too_large` and an integer `limit`), the handshake that announced the limits may be stale: the client forgets it, prepares the tree again on a fresh one and sends the request once more, as `mthds`'s client does. A `files` map given as is was not prepared from the handshake, so it is not sent again, and neither is a `start` under an idempotency key, since the platform binds the key to the refusal it stores.
|
|
50
50
|
|
|
51
51
|
**Stopping a call.** A call that takes a `signal` (`validate`, `startAndWaitForResult`, the crate routes, `prepareInputs`) reads it before each step a `directory`, `contents` or `tree` costs and hands it to the step's request, so an abort stops the version handshake, the directory's listing, the blob route, a file's read and an upload already under way, and nothing further starts.
|
|
52
52
|
|
|
53
53
|
A `MethodTree` reads a file again whenever its bytes are sent, inline or as an upload, and checks it against the hash its listing recorded, so a file changed since the listing is refused by `mthds` rather than sent as another tree than the one listed. Apart from listing a directory, sending a tree reads no Node module: hashing is Web Crypto's, and Base64 is written by the SDK.
|
|
54
54
|
|
|
55
|
-
**What is uploaded is what the listing names.** Before each upload the client hashes the bytes a tree's `readFile` gives and refuses them, with a `RequestArgumentError`, unless they have the size and the SHA-256 the tree lists for them: a blob is stored under its hash for the whole organization, so a hand-built `MethodTreeSource` whose `readFile` disagrees with its listing never stores other bytes under that hash. An answer of `POST /v1/blobs/missing` asking for a blob the tree does not hold is the platform's fault, not the caller's: it is an `ApiResponseError` of an answer the SDK cannot read,
|
|
55
|
+
**What is uploaded is what the listing names.** Before each upload the client hashes the bytes a tree's `readFile` gives and refuses them, with a `RequestArgumentError`, unless they have the size and the SHA-256 the tree lists for them: a blob is stored under its hash for the whole organization, so a hand-built `MethodTreeSource` whose `readFile` disagrees with its listing never stores other bytes under that hash. An answer of `POST /v1/blobs/missing` asking for a blob the tree does not hold is the platform's fault, not the caller's: it is an `ApiResponseError` of an answer the SDK cannot read, `client.response_unreadable`, thrown before any upload. An upload that fails throws `MethodFileTransferError` with `operation` `upload`, and the request is not sent or the method not saved ([below](#when-a-transfer-fails)).
|
|
56
56
|
|
|
57
|
-
**A blob that went missing.** A request whose hash entries name a blob the API does not hold is refused with a `422` `missing_blobs`
|
|
57
|
+
**A blob that went missing.** A request whose hash entries name a blob the API does not hold is refused with a `422` `request.blobs_missing` whose `params.missing_blobs` lists them all, which also releases a start's idempotency key. A request built from a `directory`, `contents` or `tree` uploads every blob it names first, so it meets this only if a blob was removed between the upload and the request. The client answers it as `mthds`'s client does: when the listed blobs are ones the tree holds, it asks the blob route for them again, uploads them and sends the request once more; any other answer is thrown, so sending the same call again asks the blob route afresh and uploads what is missing.
|
|
58
58
|
|
|
59
59
|
On the crate routes, `read_scope` is the scope the blob route is asked under, so the blobs are uploaded into the store the request's hash entries are read from; the hosted platform reads the caller's organization whatever the request says ([crate-routes.md](./crate-routes.md#the-shared-envelope)).
|
|
60
60
|
|
|
61
61
|
## The files a step reads
|
|
62
62
|
|
|
63
|
-
A file a step reads, such as a `PipeDocGen` step's `template_file` (the Word, Excel or PowerPoint template it fills, or the HTML template it prints as a PDF), is a file of the tree like any other, at the tree path the step names from the root. A `directory` sends it with the bundles; a `contents` or `files` map carries it under its tree path. A step that names a file the tree does not hold cannot load: on `validate`, `pipeIo`, `resolve` and `codegen` that is an `is_valid: false` verdict whose
|
|
63
|
+
A file a step reads, such as a `PipeDocGen` step's `template_file` (the Word, Excel or PowerPoint template it fills, or the HTML template it prints as a PDF), is a file of the tree like any other, at the tree path the step names from the root. A `directory` sends it with the bundles; a `contents` or `files` map carries it under its tree path. A step that names a file the tree does not hold cannot load: on `validate`, `pipeIo`, `resolve` and `codegen` that is an `is_valid: false` verdict whose problem item says the file is missing (`method.resource_missing`), `prepareInputs` throws it as a `MethodLoadError`, and on `execute` and `start` it is a `422` problem whose `errors` say the same.
|
|
64
64
|
|
|
65
65
|
### The template check's warnings
|
|
66
66
|
|
|
67
|
-
A dry run hands an office template file of the tree to the document engine's template check. An error finding fails the step's dry run, and so the verdict, as a
|
|
67
|
+
A dry run hands an office template file of the tree to the document engine's template check. An error finding fails the step's dry run, and so the verdict, as a problem item on the step. A warning finding, such as a field of the template that matches no input, rides the valid verdict's `warnings` as a problem item coded `pipelex.docgen.template_warning`:
|
|
68
68
|
|
|
69
69
|
| Member | Value |
|
|
70
70
|
| --- | --- |
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `message` | The finding in words |
|
|
71
|
+
| `code` | `pipelex.docgen.template_warning` |
|
|
72
|
+
| `location.pipe` | The `PipeDocGen` step |
|
|
73
|
+
| `params.template` | The template file as the step names it |
|
|
74
|
+
| `params.finding` | The finding in the engine's words |
|
|
75
|
+
| `detail` | The sentence a person reads, naming the template and the finding |
|
|
77
76
|
|
|
78
|
-
The warnings come in families, always in this order: `optional_force_redundant`, `input_presence_vacuous`, the
|
|
77
|
+
The warnings come in families, always in this order: `method.optional_force_redundant`, `method.input_presence_vacuous`, the hint lints (`method.hint_invalid`), then `pipelex.docgen.template_warning`. None of them flips `is_valid`.
|
|
79
78
|
|
|
80
79
|
```ts
|
|
81
80
|
if (verdict.is_valid) {
|
|
82
81
|
for (const warning of verdict.warnings) {
|
|
83
|
-
if (warning.
|
|
84
|
-
console.warn(`${warning.
|
|
82
|
+
if (warning.code === "pipelex.docgen.template_warning") {
|
|
83
|
+
console.warn(`${warning.location?.pipe ?? "?"}: ${warning.detail}`);
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
}
|
|
@@ -127,11 +126,11 @@ The save is refused, with the `ApiResponseError` of its problem, when the platfo
|
|
|
127
126
|
|
|
128
127
|
| Status and `code` | When |
|
|
129
128
|
|---|---|
|
|
130
|
-
| `422` `
|
|
131
|
-
| `422` `
|
|
132
|
-
| `422` `
|
|
133
|
-
| `422` `
|
|
134
|
-
| `413` `
|
|
129
|
+
| `422` `method.package_invalid` | The map breaks the standard's rules, a path that is not a tree path or two paths that collide among them; the problem names the path. |
|
|
130
|
+
| `422` `method.package_invalid` | The tree passes one of the deployment's limits, which the problem's `params` name (`reason` `too_large` and the `limit`). |
|
|
131
|
+
| `422` `request.invalid` | A hash entry states another size than the blob the organization holds under that hash. |
|
|
132
|
+
| `422` `request.blobs_missing` | A hash entry names bytes the organization does not hold (above). |
|
|
133
|
+
| `413` `request.too_large` | The method would leave no room for the summary a publish adds. |
|
|
135
134
|
|
|
136
135
|
## The deployment's limits
|
|
137
136
|
|
|
@@ -162,7 +161,7 @@ An empty draft lists no file and has a `draft_digest` of `null`. The listing pag
|
|
|
162
161
|
|
|
163
162
|
**A link is a bearer credential.** Anyone holding it reads the file until it expires, so it belongs in no log, message or stored record; this SDK puts it in none of its errors, not even when the answer that carried it cannot be read. A read that fails because a link expired succeeds once the method is read again.
|
|
164
163
|
|
|
165
|
-
A method whose draft names a tree the platform holds no record of answers `getMethod` with a `
|
|
164
|
+
A method whose draft names a tree the platform holds no record of answers `getMethod` with a `500` `runtime.unexpected`, and a version stored before methods were trees and never rewritten as one names no tree to serve, so `getMethodVersion` answers it with `500` `runtime.unexpected` too. An answer whose `files` is not a listing, each entry with its string `path`, `url` and `expires_at`, a `sha256` of 64 lower-case hex digits and a non-negative integer `size`, is an `ApiResponseError` naming the entry at fault. Such an answer, like any other the SDK cannot read from these two routes or from `POST /v1/blobs/missing`, reaches its error redacted: `responseBody` has every `url` member and every link's query replaced by `[redacted]`, and the error keeps no `cause`, since a parse failure can quote the body.
|
|
166
165
|
|
|
167
166
|
## Writing a tree to disk
|
|
168
167
|
|
|
@@ -179,16 +178,16 @@ Each file is downloaded through its link, at most eight at a time, with no crede
|
|
|
179
178
|
|
|
180
179
|
## When a transfer fails
|
|
181
180
|
|
|
182
|
-
`MethodFileTransferError` is thrown when a file could not be moved between this machine and storage. `operation` says which way (`upload` for a request or a save that sends a tree by hash, `download` for `writeMethodTree`), `
|
|
181
|
+
`MethodFileTransferError` is thrown when a file could not be moved between this machine and storage. `operation` says which way (`upload` for a request or a save that sends a tree by hash, `download` for `writeMethodTree`), `reason` why, `sha256` which bytes, `path` the tree path when one is known, and `status` storage's HTTP status when it answered. Neither its message nor any member carries the link, nor storage's error body, which can echo the signed request, and it keeps no `cause`: the failure `fetch` throws for a request that got no answer can quote the URL, so only its network code (`ECONNREFUSED`, `ABORT_TIMEOUT`) reaches the message.
|
|
183
182
|
|
|
184
|
-
| `
|
|
183
|
+
| `reason` | When | Its problem |
|
|
185
184
|
|---|---|---|
|
|
186
|
-
| `unreachable` | Storage gave no answer: the connection failed or the time limit ran out. |
|
|
187
|
-
| `storage_error` | Storage timed out or throttled the request (`408`, `429`) or failed (a `5xx` other than `501`). |
|
|
188
|
-
| `refused` | Storage refused the request with any other status, an expired link among them. Read the method again for fresh links. |
|
|
189
|
-
| `mismatch` | A download's bytes are not the file the listing names: another size, or another SHA-256. |
|
|
185
|
+
| `unreachable` | Storage gave no answer: the connection failed or the time limit ran out. | `runtime.unavailable` |
|
|
186
|
+
| `storage_error` | Storage timed out or throttled the request (`408`, `429`) or failed (a `5xx` other than `501`). | `runtime.unavailable` |
|
|
187
|
+
| `refused` | Storage refused the request with any other status, an expired link among them. Read the method again for fresh links. | `client.response_unreadable` naming the status, `runtime.unsupported` for a `501` |
|
|
188
|
+
| `mismatch` | A download's bytes are not the file the listing names: another size, or another SHA-256. | `client.response_unreadable` |
|
|
190
189
|
|
|
191
|
-
|
|
190
|
+
An upload to a target that asks for a create-only write (`If-None-Match`) and answers `412` is not a failure: the bytes are already stored.
|
|
192
191
|
|
|
193
192
|
## What changed from the source fields
|
|
194
193
|
|
|
@@ -56,21 +56,19 @@ The write sends no `Idempotency-Key`, as `renameOrganization` sends none. A late
|
|
|
56
56
|
|
|
57
57
|
## When a write is refused
|
|
58
58
|
|
|
59
|
-
A refused write changes nothing, whichever part of it was refused, and throws an `ApiResponseError` whose `
|
|
59
|
+
A refused write changes nothing, whichever part of it was refused, and throws an `ApiResponseError` whose `problem` is the platform's problem document; only a `503` leaves it unknown whether the write landed:
|
|
60
60
|
|
|
61
61
|
| Status | `code` | When |
|
|
62
62
|
|---|---|---|
|
|
63
|
-
| `403` | `forbidden` |
|
|
64
|
-
| `403` | `
|
|
65
|
-
| `404` | `not_found` | The organization does not exist. |
|
|
66
|
-
| `409` | `
|
|
67
|
-
| `422` | `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
**A refusal about a logo or a colour names it in `errors`**, the platform's field-level list, so the settings screen shows each sentence under the control it concerns rather than in a toast. Each entry's `field` is the slot, `square_logo` or `wide_logo`, or the colour's dotted key, such as `colors.action` or `dark_colors.header`; its `detail` is the sentence to show. A logo the platform read and refused carries a `LogoRefusalCode`, one entry per broken rule, both slots answered in one refusal:
|
|
63
|
+
| `403` | `auth.forbidden` | The caller is not the organization's admin. |
|
|
64
|
+
| `403` | `pipelex.org.mismatch` | `orgId` is not the caller's active organization, or a logo's URI is a file of another organization. |
|
|
65
|
+
| `404` | `pipelex.org.not_found` | The organization does not exist. |
|
|
66
|
+
| `409` | `pipelex.org.not_manageable` | The organization is a personal workspace, which has no branding. |
|
|
67
|
+
| `422` | `request.invalid` | A colour is not `#rrggbb`, the body holds a key the route does not take, or a logo was refused. |
|
|
68
|
+
| `422` | `pipelex.storage.uri_invalid` | A logo's URI is not a storage URI. |
|
|
69
|
+
| `503` | `runtime.unavailable` | The platform's storage failed while reading or copying a logo, or its database failed or could not be reached, so the write may have landed or not. Its `retry` is `yes`: the same `input` sent again is safe, and `getBranding` reads what the branding holds. |
|
|
70
|
+
|
|
71
|
+
**A refusal about a logo or a colour names it in its problem's `errors`**, one problem item per refused logo or colour, so the settings screen shows each sentence under the control it concerns rather than in a toast. Each item's `location.field` is the slot, `square_logo` or `wide_logo`, or the colour's dotted key, such as `colors.action` or `dark_colors.header`; its `detail` is the sentence to show. A logo the platform read and refused carries one item per broken rule, both slots answered in one refusal, each item's `code` one `LogoRefusalCode` names:
|
|
74
72
|
|
|
75
73
|
| `code` | Example `detail` |
|
|
76
74
|
|---|---|
|
|
@@ -85,16 +83,16 @@ A refused write changes nothing, whichever part of it was refused, and throws an
|
|
|
85
83
|
| `logo_not_wide` | The wide logo is 600 × 500 px, 1.2 times as wide as it is tall; a wide logo must be at least 1.5 times as wide as it is tall. |
|
|
86
84
|
| `logo_too_short` | The wide logo is 240 × 48 px; a wide logo must be at least 64 px tall. |
|
|
87
85
|
|
|
88
|
-
The two refusals of a logo URI that come before any file is read, `
|
|
86
|
+
The two refusals of a logo URI that come before any file is read, `pipelex.storage.uri_invalid` and another organization's `pipelex.org.mismatch`, name the slot the same way, with the refusal's code on the item. Reading one slot's sentences is the same filter in every case:
|
|
89
87
|
|
|
90
88
|
```ts
|
|
91
89
|
try {
|
|
92
90
|
await client.updateOrganizationBranding(orgId, { square_logo: uri });
|
|
93
91
|
} catch (err) {
|
|
94
92
|
if (!(err instanceof ApiResponseError)) throw err;
|
|
95
|
-
const underSquare = (err.errors ?? [])
|
|
96
|
-
.filter((
|
|
97
|
-
.map((
|
|
93
|
+
const underSquare = (err.problem.errors ?? [])
|
|
94
|
+
.filter((item) => item.location?.field === "square_logo")
|
|
95
|
+
.map((item) => item.detail);
|
|
98
96
|
// Show `underSquare` under the square logo's slot; an error naming no field goes in a toast.
|
|
99
97
|
}
|
|
100
98
|
```
|
package/docs/run-results.md
CHANGED
|
@@ -43,7 +43,7 @@ const results = await client.waitForResult(runId, { artifacts: ["working_memory"
|
|
|
43
43
|
|
|
44
44
|
**Absent versus null.** With a selection, an artifact the caller did not name is absent from the result, reading `undefined`, while one it named that the run never wrote is `null`. So `undefined` means "not asked for" and `null` means "asked for, not there". That is also why `main_stuff` is declared optional: it is never null on a completed run, but it is absent from a read that left it out, and `MissingMainStuffError` is thrown only by a read that asked for it — one with no selection, or one naming `main_stuff`.
|
|
45
45
|
|
|
46
|
-
An empty selection or a name outside the list is a `RequestArgumentError` thrown before any request, `
|
|
46
|
+
An empty selection or a name outside the list is a `RequestArgumentError` thrown before any request, `client.argument_invalid`, the same refusal the platform would answer with a `400`. `waitForResult` and `startAndWaitForResult` take the same `artifacts` in their poll options and send it on every poll; `startAndWaitForResult` refuses a bad selection before it starts the run. Against a bare runner the selection has nothing to narrow: the blocking fallback returns every artifact the runner sent. `downloadArtifacts` given a `run_id` asks for its scope's artifact alone.
|
|
47
47
|
|
|
48
48
|
## `pipeline_run_id` — the durable handle
|
|
49
49
|
|
|
@@ -79,7 +79,7 @@ It is never called on the blocking path, a bare runner's `POST /v1/execute` or t
|
|
|
79
79
|
|
|
80
80
|
**Knowing whether a run may exist.** `onStarting`, the other callback `StartAndWaitForResultOptions` takes, is called right before each request that may create a run is sent: `POST /v1/start`, and the blocking `POST /v1/execute` of a bare runner or of the fallback to it, so it is called twice when a runner that looked hosted refuses the start. Until it is called no run exists, and once the `signal` has aborted it is not called and no such request is sent, so a caller that stops waiting before then can say that no run was started; from then until `onStarted`, a run may exist that the API has not yet named. It runs synchronously and its return value is ignored; an exception it throws propagates before the request is sent. The `pipelex-sdk` command words its interrupt message by it ([`cli.md`](cli.md)).
|
|
81
81
|
|
|
82
|
-
**A failed start says whether a run may exist.** An error from the start, or from the blocking execute,
|
|
82
|
+
**A failed start says whether a run may exist.** An error from the start, or from the blocking execute, whose request may have created a run although the call failed is `client.outcome_unknown`, its `retry` being `outcome_unknown`, so a person looks the run up in the run history before starting it again ([`errors.md`](errors.md#a-run-that-may-have-started--outcome_unknown)). Once `onStarted` has been called the run exists and the caller holds its id, so an error while the composite waits started nothing: its `retry` is about waiting again on that id with `waitForResult`, never about calling `startAndWaitForResult` again, which would start a second run.
|
|
83
83
|
|
|
84
84
|
## A degraded status — `degraded` and `degradation`
|
|
85
85
|
|
|
@@ -90,7 +90,7 @@ It is never called on the blocking path, a bare runner's `POST /v1/execute` or t
|
|
|
90
90
|
| `reason` | What holds | `status` | What to tell the person |
|
|
91
91
|
|---|---|---|---|
|
|
92
92
|
| `status_unavailable` | The platform could not reach the workflow engine. | The last one recorded. | Nothing about the run, which may be fine: the status is not fresh, and the next read comes after `retry_after_seconds`. |
|
|
93
|
-
| `workflow_task_failing` | The workflow task that drives the run has failed `failed_attempts` times in a row since `failing_since`, so the run is not making progress. | Live. | The run is stuck. The workflow engine keeps retrying, and if the task is still failing at `ends_at` the platform ends the run `FAILED`, with a
|
|
93
|
+
| `workflow_task_failing` | The workflow task that drives the run has failed `failed_attempts` times in a row since `failing_since`, so the run is not making progress. | Live. | The run is stuck. The workflow engine keeps retrying, and if the task is still failing at `ends_at` the platform ends the run `FAILED`, with a problem of its own ([errors.md](./errors.md#a-failed-run--runfailederror)). |
|
|
94
94
|
|
|
95
95
|
```ts
|
|
96
96
|
const run = await client.getRunStatus(runId);
|
|
@@ -138,7 +138,7 @@ const results = await client.waitForResult(runId, {
|
|
|
138
138
|
- **`startAndWaitForResult` honours it on the durable path only.** Its blocking fallback, a bare runner's `POST /v1/execute`, has no run to read, so `onProgress` is never called there.
|
|
139
139
|
- **The callback runs synchronously** and its return value is ignored. An exception it throws propagates out of the wait, as one thrown by `onPoll` does, and the run keeps going on the server.
|
|
140
140
|
|
|
141
|
-
**Reading it yourself: `getRunProgress(runId)`.** It returns the snapshot as the platform answered it, the `RunProgress`. A pending run, and a run that has written no progress event yet, answer with no invocation. When the workflow engine cannot be reached the read still answers `200`: its `degradation` reads `status_unavailable`, its `status` is the last one recorded and no invocation carries a health annotation. A run that does not exist, or belongs to another organization, is the platform's `404`, an `ApiResponseError`, and a server without the route, a bare runner or a hosted API older than it, is a `RunLifecycleUnavailableError`. The members the freshness rule and a timeline lean on are checked: an answer whose `version` is not a non-negative integer, whose `pipeline_run_id`, `mode`, `status`, `assembled_at` or `summary` is not a string, whose `invocations` is not a list, or one of whose invocations misses its path, pipe identity, status or times, is an `ApiResponseError` for an answer the SDK cannot read. The snapshot's `degradation` and each invocation's are checked field by field as the status read's are, and one whose `reason` is not a string is dropped,
|
|
141
|
+
**Reading it yourself: `getRunProgress(runId)`.** It returns the snapshot as the platform answered it, the `RunProgress`. A pending run, and a run that has written no progress event yet, answer with no invocation. When the workflow engine cannot be reached the read still answers `200`: its `degradation` reads `status_unavailable`, its `status` is the last one recorded and no invocation carries a health annotation. A run that does not exist, or belongs to another organization, is the platform's `404`, an `ApiResponseError`, and a server without the route, a bare runner or a hosted API older than it, is a `RunLifecycleUnavailableError`. The members the freshness rule and a timeline lean on are checked: an answer whose `version` is not a non-negative integer, whose `pipeline_run_id`, `mode`, `status`, `assembled_at` or `summary` is not a string, whose `invocations` is not a list, or one of whose invocations misses its path, pipe identity, status or times, is an `ApiResponseError` for an answer the SDK cannot read. The snapshot's `degradation` and each invocation's are checked field by field as the status read's are, and one whose `reason` is not a string is dropped; an invocation's `last_failure` is kept only when its `problem` is a problem document (`isProblem` in `mthds/protocol`), and its `at` only when it is a string. So no health annotation fails the read. Members the SDK does not name are relayed as sent.
|
|
142
142
|
|
|
143
143
|
### The snapshot
|
|
144
144
|
|
|
@@ -169,7 +169,7 @@ An **invocation** is one run of one pipe inside the run, named by its `path`: th
|
|
|
169
169
|
| `batch` | `ProgressBatch`, optional | On a `PipeBatch` that has fanned out, `{ total, done, running, failed }`: `done` counts the items succeeded or skipped, and an item scheduled or canceled is in none of the three. |
|
|
170
170
|
| `condition` | `ProgressCondition`, optional | On a `PipeCondition` that has resolved, `{ selected_outcome }`, the key its value matched, or `null` for its default outcome. |
|
|
171
171
|
| `attempts` | `number`, optional | Health: how many times its work has been tried, present only when more than once. |
|
|
172
|
-
| `last_failure` | `ProgressFailure`, optional | Health: `{
|
|
172
|
+
| `last_failure` | `ProgressFailure`, optional | Health: `{ problem, at? }`, the latest failure of its work. `problem` is the standard's `Problem`, in the caller's view as the run reads serve a failed run's problem: the problem that ended the invocation when it is `failed`, and otherwise the problem of the latest failure of an attempt its engine is trying again, `runtime.unexpected` for a failure only the engine observed. Branch on its `code`, never on the wording of its `detail`. `at` is when it failed, absent when not recorded. |
|
|
173
173
|
| `degradation` | `RunDegradation`, optional | Health: the run is stuck here, in the run status's own words — the status read's `degradation`, `workflow_task_failing`, placed on the run's root or on the batch item whose execution keeps failing to advance. |
|
|
174
174
|
|
|
175
175
|
The health annotations are what the workflow engine reports, so an absent one means that nothing was observed, never that the engine looked and found all well. They reuse the run status's `RunDegradation` rather than a shape of their own, so the code that shows a degraded status shows a stuck invocation too.
|
|
@@ -221,14 +221,14 @@ switch (state.state) {
|
|
|
221
221
|
console.log(`not finished — poll again in ${state.retry_after_seconds ?? 2}s`);
|
|
222
222
|
break;
|
|
223
223
|
case "failed":
|
|
224
|
-
// `
|
|
224
|
+
// `problem` is `run.failed`; `error` is the run's own problem, or null.
|
|
225
225
|
console.error(`run ended as ${state.status}: ${state.message}`);
|
|
226
|
-
if (state.error
|
|
226
|
+
if (state.error) console.error(`${state.error.code}: ${state.error.next_step.detail}`);
|
|
227
227
|
break;
|
|
228
228
|
}
|
|
229
229
|
```
|
|
230
230
|
|
|
231
|
-
`getRunResult` is the single-shot lookup and returns that discriminated state. `waitForResult(runId)` drives the same lookup in a loop, honouring the server's `Retry-After`, and returns the `RunResults` directly — throwing `RunFailedError` on a terminal non-completed status and `RunTimeoutError` when the budget runs out. The `failed` arm and `RunFailedError` carry the same facts: the run's `status`, the `message` naming the reason,
|
|
231
|
+
`getRunResult` is the single-shot lookup and returns that discriminated state. `waitForResult(runId)` drives the same lookup in a loop, honouring the server's `Retry-After`, and returns the `RunResults` directly — throwing `RunFailedError` on a terminal non-completed status and `RunTimeoutError` when the budget runs out. The `failed` arm and `RunFailedError` carry the same facts: the run's `status`, the `message` naming the reason, `problem`, the platform's `run.failed` document, and the run's own problem, which `run.failed` nests as `run_error`: the arm's `error`, `null` when the run ended without one, and the error's `runError`. [`errors.md`](./errors.md#a-failed-run--runfailederror) describes both.
|
|
232
232
|
|
|
233
233
|
## `working_memory` — every named stuff of the run
|
|
234
234
|
|
package/package.json
CHANGED
package/dist/error-models.d.ts
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error-report wire models — a failed run's stored report, and the typed members of a
|
|
3
|
-
* problem document.
|
|
4
|
-
*
|
|
5
|
-
* **The runner owns these shapes; this SDK follows them.** A run that fails reports why as
|
|
6
|
-
* the runner's `ErrorReport` (`pipelex.base_exceptions`), which the hosted platform stores
|
|
7
|
-
* whole on the run row as `error` and serves through the runner's STRICT disclosure: on the
|
|
8
|
-
* status read (`RunRead.error`), on the run records (`PipelineRun.error`,
|
|
9
|
-
* `RunHistoryItem.error`), and inside the problem document of the results read's `409`, where
|
|
10
|
-
* the client lifts it onto the failed arm of
|
|
11
|
-
* `RunResultState` and onto `RunFailedError.error`. The same classification fields
|
|
12
|
-
* (`error_domain`, `user_action`, …) ride a runner-rendered problem document as extension
|
|
13
|
-
* members, which is why `ApiResponseError` types its members with the models declared here.
|
|
14
|
-
*
|
|
15
|
-
* Every field is optional and every interface keeps an index signature, for the reason
|
|
16
|
-
* `TokensUsageRecord` gives: the runner adds fields without asking this SDK, and a field this
|
|
17
|
-
* version does not name still reaches the caller. The enum-ish fields (`error_domain`,
|
|
18
|
-
* `error_category`, `user_action.kind`) are open sets on the wire and stay `string`, never
|
|
19
|
-
* frozen unions, so a value the runner adds is not an SDK break; their known values are listed
|
|
20
|
-
* where they are declared.
|
|
21
|
-
*
|
|
22
|
-
* **A stored report is checked, not cast.** Every read that hands one back runs it through
|
|
23
|
-
* `readRunErrorReport`, which keeps each named field only when it has the type declared here and
|
|
24
|
-
* reads it as absent otherwise, as the Python twin does: a report written by an older runner, or
|
|
25
|
-
* stored by hand, cannot hand a consumer a number where a string is typed. The client checks the
|
|
26
|
-
* nested members of a problem document with the same readers, so `ApiResponseError`'s
|
|
27
|
-
* `providerMetadata`, `migration`, `validationErrors` and `errors` hold to their types as a stored
|
|
28
|
-
* report's do.
|
|
29
|
-
*
|
|
30
|
-
* **The platform serves the STRICT projection; this SDK strips nothing further.** The run row
|
|
31
|
-
* keeps the runner's VERBOSE report as the operators' record, and every read that hands it to a
|
|
32
|
-
* caller serves the rule the hosted runner applies to an error on `execute`: `error_type`,
|
|
33
|
-
* `title`, `type_uri`, `error_domain`, `error_category`, `retryable` and `validation_errors`
|
|
34
|
-
* pass through; `message` and `user_action` pass through only when `caller_facing_message` is
|
|
35
|
-
* `true`, which the served report then keeps, and otherwise `message` is the placeholder
|
|
36
|
-
* `An internal error occurred.` while `user_action` and the flag are absent; `provider_metadata`
|
|
37
|
-
* keeps only `status_code` and `retry_after_seconds`; `model`, `provider` and `migration` are
|
|
38
|
-
* absent. The reports the platform writes itself are caller-facing copy, so they keep their
|
|
39
|
-
* message and their next step. A platform run locally with `ERROR_DISCLOSURE=verbose` serves the
|
|
40
|
-
* report whole, which is why the types still name every member the runner writes. Deciding what
|
|
41
|
-
* a person should see is each consumer's presentation; the report arrives here as served,
|
|
42
|
-
* members this SDK does not name included.
|
|
43
|
-
*/
|
|
44
|
-
import type { ValidationErrorItem } from "./models.js";
|
|
45
|
-
/**
|
|
46
|
-
* The next step an error advises — the runner's `UserAction`, carried as `user_action` on a
|
|
47
|
-
* stored report and on a runner's problem document. `kind` names the category of advice, so a
|
|
48
|
-
* consumer can render consistent guidance; `detail` is the advice itself, in words (a billing
|
|
49
|
-
* URL, a retry hint, the model to change).
|
|
50
|
-
*
|
|
51
|
-
* Known `kind` values: `wait_and_retry`, `check_billing`, `check_credentials`, `change_input`,
|
|
52
|
-
* `change_model`, `contact_support`, `unknown`. The set is the runner's, so it is typed open.
|
|
53
|
-
* It is the hosted plane's own member, which predates the standard's problem document: there the
|
|
54
|
-
* next step is the problem's `next_step`, whose `kind` is a closed list of its own.
|
|
55
|
-
*/
|
|
56
|
-
export interface UserAction {
|
|
57
|
-
kind: string;
|
|
58
|
-
detail: string;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* What the inference provider's SDK said about a failed call — the runner's
|
|
62
|
-
* `ProviderErrorMetadata`. Present on a report whose failure came back from a model provider.
|
|
63
|
-
* `message` is the provider SDK's own text, relayed raw; the provider's response body never
|
|
64
|
-
* crosses the wire, because the runner excludes it from every serialization. A hosted run read
|
|
65
|
-
* keeps only `status_code` and `retry_after_seconds`, the client hints; the other members reach a
|
|
66
|
-
* caller only from a server that discloses errors VERBOSE, such as a platform run locally with
|
|
67
|
-
* `ERROR_DISCLOSURE=verbose`.
|
|
68
|
-
*
|
|
69
|
-
* **The hosted store turns its numbers into strings.** A report read back from the platform's
|
|
70
|
-
* run store carries `status_code` and `retry_after_seconds` as JSON strings (`"404"`,
|
|
71
|
-
* `"1.5"`), because the store hands its numbers back as decimals that the platform serializes
|
|
72
|
-
* as strings. A problem document rendered by a runner carries them as numbers. Both are typed,
|
|
73
|
-
* so read them with `Number(...)` when you need the value.
|
|
74
|
-
*/
|
|
75
|
-
export interface ProviderErrorMetadata {
|
|
76
|
-
provider?: string | null;
|
|
77
|
-
sdk_exception_type?: string | null;
|
|
78
|
-
message?: string | null;
|
|
79
|
-
/** The provider's HTTP status, when it answered one. */
|
|
80
|
-
status_code?: number | string | null;
|
|
81
|
-
/** The provider's own request id — what its support desk asks for. */
|
|
82
|
-
request_id?: string | null;
|
|
83
|
-
retry_after_seconds?: number | string | null;
|
|
84
|
-
provider_error_code?: string | null;
|
|
85
|
-
[extension: string]: unknown;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* A pending configuration migration that explains the failure — the runner's
|
|
89
|
-
* `MigrationErrorBlock`. Present only on a configuration failure whose raiser scanned the
|
|
90
|
-
* host's configuration directories; a consumer branches on its presence. `plans` is carried
|
|
91
|
-
* opaquely: it is the shape `pipelex-agent migrate --dry-run --format json` emits, which no
|
|
92
|
-
* published package declares.
|
|
93
|
-
*/
|
|
94
|
-
export interface MigrationErrorBlock {
|
|
95
|
-
/** The command that applies whatever can be applied without a decision. */
|
|
96
|
-
remedy?: string | null;
|
|
97
|
-
/** Whether running `remedy` would rewrite any file. */
|
|
98
|
-
would_write?: boolean | null;
|
|
99
|
-
/** Whether something here is a person's to resolve rather than the tool's. */
|
|
100
|
-
needs_attention?: boolean | null;
|
|
101
|
-
plans?: Record<string, unknown>[] | null;
|
|
102
|
-
[extension: string]: unknown;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Why a run failed — the runner's `ErrorReport`, typed with every field it carries.
|
|
106
|
-
*
|
|
107
|
-
* The one type for a failed run's report wherever the SDK hands it back: `RunPublic.error`
|
|
108
|
-
* (and so `RunRead.error` on the status read), `PipelineRun.error` on the run records, `error`
|
|
109
|
-
* on the failed arm of `RunResultState` (the results read's `409`), and `RunFailedError.error`
|
|
110
|
-
* when `waitForResult`, `startAndWaitForResult` or an artifact download throws for a run that
|
|
111
|
-
* ended without a result.
|
|
112
|
-
*
|
|
113
|
-
* **Branch on `error_domain`, `type_uri` and `retryable`**, never on the wording of `message`.
|
|
114
|
-
* `error_type` is the runner's open-ended exception class name: finer than `error_domain`,
|
|
115
|
-
* useful in a support line, but not a closed set to match against. Which fault's identity a run
|
|
116
|
-
* failure's report carries, and how its `message` names the failing pipe, is the runner's to
|
|
117
|
-
* decide; read them as given.
|
|
118
|
-
*
|
|
119
|
-
* The runner writes the report of a run that fails while it runs. A run the platform ends or
|
|
120
|
-
* settles itself carries one the platform wrote in the same shape, as caller-facing copy:
|
|
121
|
-
* `WorkflowTaskKeptFailingError` for a workflow task that kept failing (the run ends `FAILED`,
|
|
122
|
-
* not `TERMINATED`), `RunTimedOutError` for a timeout and `RunWorkflowNotFoundError` for a
|
|
123
|
-
* workflow that vanished. A `CANCELLED`, `TERMINATED` or `TIMED_OUT` run holds a report when a
|
|
124
|
-
* completion callback carried one, and a `TIMED_OUT` run otherwise holds the platform's timeout
|
|
125
|
-
* report. A report is `null` on a completed run and where a run has none — one whose start
|
|
126
|
-
* failed, a blocking `execute` run, whose answer carried its reason, one cancelled, terminated or
|
|
127
|
-
* given its status by hand with no completion callback carrying a report, one that ended before
|
|
128
|
-
* the platform wrote reports of its own — so the absence of a report says nothing about why.
|
|
129
|
-
*
|
|
130
|
-
* What the platform serves of a report is the runner's STRICT projection (see the module
|
|
131
|
-
* comment), so the members the projection drops are absent on a hosted read.
|
|
132
|
-
*/
|
|
133
|
-
export interface RunErrorReport {
|
|
134
|
-
/**
|
|
135
|
-
* The runner's exception class name (`LLMCompletionError`, `PipeRunError`, …) — an open
|
|
136
|
-
* set, for display and support, not for branching.
|
|
137
|
-
*/
|
|
138
|
-
error_type?: string | null;
|
|
139
|
-
/**
|
|
140
|
-
* What went wrong. The platform serves the author's copy only when `caller_facing_message` is
|
|
141
|
-
* `true`, and the placeholder `An internal error occurred.` otherwise.
|
|
142
|
-
*/
|
|
143
|
-
message?: string | null;
|
|
144
|
-
/** A stable human label for the error class (`LLM completion`). */
|
|
145
|
-
title?: string | null;
|
|
146
|
-
/** The stable URI naming the error class — a branch field, and where its documentation lives. */
|
|
147
|
-
type_uri?: string | null;
|
|
148
|
-
/**
|
|
149
|
-
* Who can fix it, the coarse branch field. Known values: `input` (the caller — a malformed
|
|
150
|
-
* bundle, a bad input), `config` (a configuration change — a model not served, a missing
|
|
151
|
-
* secret), `runtime` (nobody beforehand — a provider outage during execution).
|
|
152
|
-
*/
|
|
153
|
-
error_domain?: string | null;
|
|
154
|
-
/**
|
|
155
|
-
* A finer classification of an inference failure, when the runner has one. Known values:
|
|
156
|
-
* `transient`, `configuration`, `content`, `capacity`, `ambiguous`, `unknown`.
|
|
157
|
-
*/
|
|
158
|
-
error_category?: string | null;
|
|
159
|
-
/** Whether retrying the same run can succeed. Absent or `null` means unknown, never "no". */
|
|
160
|
-
retryable?: boolean | null;
|
|
161
|
-
/** The next step the runner advises. The platform serves it only beside caller-facing copy. */
|
|
162
|
-
user_action?: UserAction | null;
|
|
163
|
-
/**
|
|
164
|
-
* The model the failing call used, when the failure is an inference failure. Absent on a
|
|
165
|
-
* hosted read, whose STRICT projection drops it.
|
|
166
|
-
*/
|
|
167
|
-
model?: string | null;
|
|
168
|
-
/**
|
|
169
|
-
* The provider the failing call reached, when the failure is an inference failure. Absent on
|
|
170
|
-
* a hosted read, whose STRICT projection drops it.
|
|
171
|
-
*/
|
|
172
|
-
provider?: string | null;
|
|
173
|
-
/**
|
|
174
|
-
* What the provider's SDK said, when the failure came back from a provider. A hosted read
|
|
175
|
-
* keeps only its `status_code` and `retry_after_seconds`.
|
|
176
|
-
*/
|
|
177
|
-
provider_metadata?: ProviderErrorMetadata | null;
|
|
178
|
-
/**
|
|
179
|
-
* True when `message` was written as caller-facing copy. The runner emits it only when true,
|
|
180
|
-
* and the platform keeps it on a caller-facing report and leaves it out otherwise, so it is how
|
|
181
|
-
* a consumer tells the author's copy from the placeholder.
|
|
182
|
-
*/
|
|
183
|
-
caller_facing_message?: boolean | null;
|
|
184
|
-
/**
|
|
185
|
-
* The structured diagnostics of a bundle that failed validation — the same items the
|
|
186
|
-
* validate report and a `422`'s `ApiResponseError.validationErrors` carry.
|
|
187
|
-
*/
|
|
188
|
-
validation_errors?: ValidationErrorItem[] | null;
|
|
189
|
-
/**
|
|
190
|
-
* A pending configuration migration that explains the failure. Absent on a hosted read, whose
|
|
191
|
-
* STRICT projection drops it.
|
|
192
|
-
*/
|
|
193
|
-
migration?: MigrationErrorBlock | null;
|
|
194
|
-
/** Fields a newer runner adds, reachable before this SDK names them. */
|
|
195
|
-
[extension: string]: unknown;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* One field-level failure of a request — an item of the platform problem document's
|
|
199
|
-
* `errors[]`. `field` is the dotted path to the offending attribute, `code` a stable sub-code
|
|
200
|
-
* (`invalid_format`, `out_of_range`, …), `detail` optional human text.
|
|
201
|
-
*/
|
|
202
|
-
export interface FieldError {
|
|
203
|
-
field?: string | null;
|
|
204
|
-
code?: string | null;
|
|
205
|
-
detail?: string | null;
|
|
206
|
-
[extension: string]: unknown;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* The members of an RFC 9457 problem document that `ApiResponseError` exposes beyond its
|
|
210
|
-
* message, as the client parsed them: the standard's own `type`, `title` and `instance`, the
|
|
211
|
-
* request id, and the extension members the runner and the platform add to classify the
|
|
212
|
-
* failure. Every member is optional — a server sends what it knows, and a body that is not a
|
|
213
|
-
* problem document carries none of them.
|
|
214
|
-
*
|
|
215
|
-
* These are the hosted plane's members, which predate the standard's problem document: the
|
|
216
|
-
* standard's reading of the same answer is `ApiResponseError.problem`, and the two never share a
|
|
217
|
-
* slot, so the platform's field-level `errors` here and the problem items of `problem.errors`
|
|
218
|
-
* stay apart.
|
|
219
|
-
*/
|
|
220
|
-
export interface ProblemDetails {
|
|
221
|
-
/** RFC 9457 `type` — the stable URI of the error class. */
|
|
222
|
-
type?: string;
|
|
223
|
-
/** RFC 9457 `title` — the short human label of the error class. */
|
|
224
|
-
title?: string;
|
|
225
|
-
/** RFC 9457 `instance` — the occurrence (a request path or a request URN). */
|
|
226
|
-
instance?: string;
|
|
227
|
-
/** The request's correlation id: the body's `request_id`, else the `X-Request-ID` response header. */
|
|
228
|
-
requestId?: string;
|
|
229
|
-
/** The body's `error_domain` — `input`, `config` or `runtime`. */
|
|
230
|
-
errorDomain?: string;
|
|
231
|
-
/** The body's `error_category` — the finer classification of an inference failure. */
|
|
232
|
-
errorCategory?: string;
|
|
233
|
-
/** The body's `retryable` — whether retrying the same request can plausibly succeed. */
|
|
234
|
-
retryable?: boolean;
|
|
235
|
-
/** The body's `user_action` — what the caller should do next. */
|
|
236
|
-
userAction?: UserAction;
|
|
237
|
-
/** The body's `model` — the model an inference failure used. */
|
|
238
|
-
model?: string;
|
|
239
|
-
/** The body's `provider` — the provider an inference failure reached. */
|
|
240
|
-
provider?: string;
|
|
241
|
-
/** The body's `provider_metadata` — what the provider's SDK said. */
|
|
242
|
-
providerMetadata?: ProviderErrorMetadata;
|
|
243
|
-
/** The body's `migration` — a pending configuration migration that explains the failure. */
|
|
244
|
-
migration?: MigrationErrorBlock;
|
|
245
|
-
/** The platform's field-level `errors[]`. */
|
|
246
|
-
errors?: FieldError[];
|
|
247
|
-
}
|
|
248
|
-
/** Whether a value is a plain object: an object that is neither `null` nor an array. */
|
|
249
|
-
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
250
|
-
/**
|
|
251
|
-
* Drop each of `fields` from `record` when it is present and fails `fits`. `null` always fits,
|
|
252
|
-
* since every field of these shapes allows it. Internal: the run status read's degradation
|
|
253
|
-
* (`readRunDegradation` in `runs.ts`) is checked with it too.
|
|
254
|
-
*/
|
|
255
|
-
export declare function dropUnfit(record: Record<string, unknown>, fields: readonly string[], fits: (value: unknown) => boolean): void;
|
|
256
|
-
/**
|
|
257
|
-
* `provider_metadata`, its named string fields kept as strings and `status_code` and
|
|
258
|
-
* `retry_after_seconds` as a number or a string; its other members are relayed as sent.
|
|
259
|
-
*/
|
|
260
|
-
export declare function readProviderMetadata(value: Record<string, unknown>): ProviderErrorMetadata;
|
|
261
|
-
/**
|
|
262
|
-
* `migration`, its `remedy` kept as a string, `would_write` and `needs_attention` as booleans, and
|
|
263
|
-
* `plans` as an array keeping only its objects; its other members are relayed as sent.
|
|
264
|
-
*/
|
|
265
|
-
export declare function readMigration(value: Record<string, unknown>): MigrationErrorBlock;
|
|
266
|
-
/**
|
|
267
|
-
* A validation item is kept when it is an object with a string `category` and `message`, its other
|
|
268
|
-
* members relayed as sent. It checks a problem document's items and a stored report's only:
|
|
269
|
-
* `validate()` and the crate routes hand their reports' items back unchecked.
|
|
270
|
-
*/
|
|
271
|
-
export declare function isValidationItem(value: unknown): value is ValidationErrorItem;
|
|
272
|
-
/**
|
|
273
|
-
* An item of a platform problem document's `errors[]`, its `field`, `code` and `detail` kept when
|
|
274
|
-
* they are strings and its other members relayed as sent.
|
|
275
|
-
*/
|
|
276
|
-
export declare function readFieldError(value: Record<string, unknown>): FieldError;
|
|
277
|
-
/**
|
|
278
|
-
* A failed run's stored report, checked field by field — the one way every read in this SDK
|
|
279
|
-
* hands a report back.
|
|
280
|
-
*
|
|
281
|
-
* - A value that is not a plain object reads as `null`, no report.
|
|
282
|
-
* - Each string field (`error_type`, `message`, `title`, `type_uri`, `error_domain`,
|
|
283
|
-
* `error_category`, `model`, `provider`) is kept when it is a string, an empty one included, and
|
|
284
|
-
* is absent otherwise. Deciding that a blank field says nothing is presentation, left to each
|
|
285
|
-
* consumer.
|
|
286
|
-
* - `retryable` and `caller_facing_message` are kept when they are booleans.
|
|
287
|
-
* - `user_action` is kept whole or not at all: an object whose `kind` and `detail` are both
|
|
288
|
-
* strings, which is what `UserAction` promises. (The Python twin keeps a partial action, its
|
|
289
|
-
* stored-report action being a lenient type of its own; this is the one place the two differ.)
|
|
290
|
-
* - `provider_metadata` is kept when it is an object, with each named field checked: the strings
|
|
291
|
-
* as strings, `status_code` and `retry_after_seconds` as a number or a string, since the hosted
|
|
292
|
-
* store serves its numbers as strings.
|
|
293
|
-
* - `migration` is kept when it is an object: `remedy` as a string, `would_write` and
|
|
294
|
-
* `needs_attention` as booleans, and `plans` as an array keeping only its objects.
|
|
295
|
-
* - `validation_errors` is kept when it is an array, keeping each item that is an object with a
|
|
296
|
-
* string `category` and a string `message`.
|
|
297
|
-
* - `null` is kept wherever the type allows it, which is every named field; and members this SDK
|
|
298
|
-
* does not name, in the report and in each nested object, are relayed as sent.
|
|
299
|
-
*
|
|
300
|
-
* Internal: every report a consumer meets comes through one of the reads that apply it.
|
|
301
|
-
*/
|
|
302
|
-
export declare function readRunErrorReport(value: unknown): RunErrorReport | null;
|