@pipelex/sdk 0.35.0 → 0.36.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 +1 -1
- package/dist/cli/present.d.ts +6 -0
- package/dist/cli/present.js +20 -3
- package/dist/cli/present.js.map +1 -1
- package/dist/cli/script.d.ts +1 -1
- package/dist/client.d.ts +41 -20
- package/dist/client.js +61 -15
- package/dist/client.js.map +1 -1
- package/dist/error-verdicts.d.ts +15 -13
- package/dist/error-verdicts.js +15 -13
- package/dist/error-verdicts.js.map +1 -1
- package/dist/errors.d.ts +10 -6
- package/dist/errors.js +10 -6
- package/dist/errors.js.map +1 -1
- package/dist/models.d.ts +14 -8
- package/dist/product-models.d.ts +11 -1
- package/dist/runs.d.ts +4 -2
- package/dist/runs.js +10 -5
- package/dist/runs.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/architecture.md +7 -7
- package/docs/cli.md +2 -1
- package/docs/errors.md +7 -7
- package/docs/input-preparation.md +1 -1
- package/docs/run-results.md +1 -1
- package/package.json +1 -1
package/docs/errors.md
CHANGED
|
@@ -34,14 +34,14 @@ try {
|
|
|
34
34
|
|
|
35
35
|
**A request the gateway cut off: `isGatewayCutOff`.** The hosted gateway gives up on a request it waits on at about 30 seconds and answers `503` or `504`, while the server may still be handling it: a `start` whose server is fetching a `method_ref`'s package, for one. `isGatewayCutOff(error, elapsedMs)` tells such a failure from a refusal: it is `true` when, at least ~28 seconds after the request was sent, the failure is a `503` or `504` answer or the client's own time limit (`ApiUnreachableError` with the code `ABORT_TIMEOUT`), and `false` before then, since a fast `503` is the API saying it did not handle the request, and for any other failure. The blocking `execute` applies it and throws `PipelineExecuteTimeoutError`; a caller timing its own start, from `startAndWaitForResult`'s `onStarting` for one, applies it to learn that a run may exist although the start failed, timing it on the monotonic clock `performance.now`, as the client does, since a change of the system's time moves `Date.now`. The fetch API cannot say whether `ABORT_TIMEOUT` ran out before the connection was made, so the rule reads it as the gateway's; with Node's own dispatcher it never does past the threshold, since undici gives up a connection that does not come after ten seconds (`UND_ERR_CONNECT_TIMEOUT`), the TLS handshake included. The Python SDK's `is_gateway_cut_off` is the same rule.
|
|
36
36
|
|
|
37
|
-
**What carries no verdict.** `errorVerdictOf` returns `undefined` for what is not an SDK failure: the `RangeError` or `TypeError` the SDK raises for an argument of the wrong type or range before any request is sent (a `timeoutMs` out of range, a malformed `appInfo`, an
|
|
37
|
+
**What carries no verdict.** `errorVerdictOf` returns `undefined` for what is not an SDK failure: the `RangeError` or `TypeError` the SDK raises for an argument of the wrong type or range before any request is sent (a `timeoutMs` out of range, a malformed `appInfo`, an artifact selection that is not an array), which names a bug in the calling code; and the caller's own abort, which the client rethrows untouched. The per-reference errors inside a `downloadArtifacts` verdict are values with a `code`, not thrown errors, and carry none either. An argument the client refuses for what it asks, such as two method selectors given to `validate` or `execute`, or a base URL with a path, is a `RequestArgumentError`, which carries a verdict like every SDK error.
|
|
38
38
|
|
|
39
39
|
### Each class's verdict
|
|
40
40
|
|
|
41
41
|
| Class | `errorDomain` | `retryable` | Why |
|
|
42
42
|
|---|---|---|---|
|
|
43
43
|
| `ApiResponseError` | the server's, else the fallback | the server's, else no for a sent `input` or `config` domain, else the fallback | See [below](#a-refused-requests-verdict). |
|
|
44
|
-
| `RequestArgumentError` | `input` | no | The client refused a call's arguments before sending any request: no run source given to `execute` or `start`, run sources or method selectors that exclude each other, a selector rule of `validate`, an empty `validateFiles`, a reserved key in `extra`, a `publishMethod` without its token, a `getMethodVersion` version that is not a positive integer,
|
|
44
|
+
| `RequestArgumentError` | `input` | no | The client refused a call's arguments before sending any request: no run source given to `execute` or `start`, run sources or method selectors that exclude each other, a selector rule of `validate`, an empty `validateFiles`, a reserved key in `extra`, a `publishMethod` without its token, a `getMethodVersion` version that is not a positive integer, a selector `parseMethodSelector` refuses, or an artifact selection that is empty or names an unknown artifact. Its options take an optional `verdict`, and the client declares `config` for a base URL that is not host-only, since it typically comes from `PIPELEX_BASE_URL`. That refusal shows the base URL's scheme and host alone and names the other parts it carried (credentials, a path, a query, a fragment) without their text, since those are where a secret travels in a URL; a value that is not an http or https URL is not shown at all. It is a `PipelineRequestError`, as the bare refusal it replaced was, and a refusal the standard's own run-source check raises keeps that original as `cause`. |
|
|
45
45
|
| `ApiUnreachableError` | `config` | yes | The address or the network must be checked, and a later attempt can get through. With the code `ABORT_TIMEOUT`, the SDK's own request timeout, it is `runtime`: the API took the request and did not answer in time. |
|
|
46
46
|
| `PipelineExecuteTimeoutError` | `input` | no | The blocking `execute` cannot outlast the gateway's limit; start the run and poll instead. |
|
|
47
47
|
| `RunFailedError` | the report's | the report's | See [a failed run](#a-failed-run--runerrorreport). |
|
|
@@ -77,9 +77,9 @@ The fallback reads the HTTP status, the platform's `code`, and whether the body
|
|
|
77
77
|
| `500`, `502`, `503`, `504`, and any `5xx` not listed here | `runtime` | yes | A fault in the service, which may pass. |
|
|
78
78
|
| Anything else | `runtime` | no | A status no refusal carries, such as the `2xx` of an answer the SDK could not read; nothing says a retry helps. |
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
The members the server sent are read first, and the fallback answers only for one it did not send: a runner's problem usually carries its own, the platform sends them on the problems it renders itself once its deployment classifies them, and a route that sends neither, as the platform's Lambda-backed routes do not yet, gets the fallback for both. **Nothing on the error says which of the two a value came from**: `problemDocument` keeps the document whole, so a reader that must tell a server-sent verdict from a derived one reads it there, as the live suite `tests/e2e/error-verdicts.e2e.ts` does. A rejected API key always gets the fallback's verdict: the hosted gateway's authorizer refuses it before the platform sees the request, with a bare `403` whose body is `{"message":"Forbidden"}`, which carries no `code`, no `type` and no verdict, so the error reads it as `config` and not retryable from the status alone.
|
|
81
81
|
|
|
82
|
-
**The verdicts are a contract with the Python SDK.** `pipelex-sdk` must apply the same fallback and declare the same verdict on each class it shares with this package. `tests/fixtures/error-verdicts.json` holds every case the two must agree on, the fallback's rows, the server-sent resolution and each class's variants, and this package's test suite drives its own code through it. The
|
|
82
|
+
**The verdicts are a contract with the Python SDK.** `pipelex-sdk` must apply the same fallback and declare the same verdict on each class it shares with this package. `tests/fixtures/error-verdicts.json` holds every case the two must agree on, the fallback's rows, the server-sent resolution and each class's variants, and this package's test suite drives its own code through it. The file is the source: `make shared-files` at the repository's root writes its byte for byte identical copy to `python/tests/fixtures/error-verdicts.json`, `make check-shared-files` fails on a stale copy, and the Python suite drives its own code through the same cases (`python/docs/errors.md`). A class or a variant only one SDK has is marked `only_in` in the file, and the other suite skips it. So a change to a verdict is made in the file here, copied, and then made in both packages.
|
|
83
83
|
|
|
84
84
|
The shapes are not this SDK's invention. The report is the runner's `ErrorReport` (in `pipelex`), stored and served by the platform exactly as the runner wrote it, and the problem members are the ones the hosted-envelope spec names, `conformance/specs/pipelex-hosted-envelope.md` in the `conformance` repository, where the cross-repo specs sit beside the tests that verify them. The types live in `src/error-models.ts`; `pipelex-sdk` (Python) carries the same fields under snake_case names.
|
|
85
85
|
|
|
@@ -167,7 +167,7 @@ Every non-2xx answer from a `/v1` route is a problem document, and the SDK throw
|
|
|
167
167
|
| `title` | `title` | The stable human label of the error class. |
|
|
168
168
|
| `serverMessage` | `detail` (or `message`) | The per-occurrence message. |
|
|
169
169
|
| `instance` | `instance` | The occurrence: a request URN (`urn:pipelex:request:<id>`) or a request path. |
|
|
170
|
-
| `code` | `code` | The platform's native code, a closed set (`conflict`, `not_found`, `validation_failed`, `pipelex_api_key_limit_reached`, …), one-to-one with `type`; `MethodErrorCode` names the method ones (see [The method codes](#the-method-codes)). |
|
|
170
|
+
| `code` | `code` | The platform's native code, a closed set (`conflict`, `not_found`, `validation_failed`, `pipelex_api_key_limit_reached`, …), one-to-one with `type`; `MethodErrorCode` names the method ones (see [The method codes](#the-method-codes)). **A branch field for a client of the platform**, absent on a refusal it relays from the runner. |
|
|
171
171
|
| `errorType` | `error_type` | The runner's native code, its open exception class name. |
|
|
172
172
|
| `errorCategory`, `model`, `provider`, `providerMetadata` | `error_category`, `model`, `provider`, `provider_metadata` | An inference failure's class and origin, as on the run report. |
|
|
173
173
|
| `migration` | `migration` | A pending configuration migration that explains the failure. |
|
|
@@ -176,7 +176,7 @@ Every non-2xx answer from a `/v1` route is a problem document, and the SDK throw
|
|
|
176
176
|
| `problemDocument` | the whole body | The decoded document, every member named or not; `undefined` when the body was not a JSON object. The record of what the server sent, verdict members included. |
|
|
177
177
|
| `status`, `statusText`, `responseBody` | the transport | The HTTP status, its text and the raw body. |
|
|
178
178
|
|
|
179
|
-
**Branch on `errorDomain` and `type`, never on the HTTP status or the message.** That is the rule the hosted-envelope spec sets
|
|
179
|
+
**Branch on `errorDomain` and `type`, never on the HTTP status or the message.** That is the rule the hosted-envelope spec sets across surfaces: `errorDomain` tells the caller's own mistake from a fault it cannot fix, and `type` names the error class with a URI that stays the same on every occurrence, and both mean the same on the runner and the platform. `code` and `errorType` are each surface's finer native code, and a client of one surface may branch on that surface's code too. On the platform `type` is `https://pipelex.com/errors/<code>`, derived from `code` one to one, so branching on either reads the same answer; the platform may add codes, so a code the caller does not know gets its generic handling. A refusal the platform relays from the runner, such as a run route's refusal to run an invalid method, carries the runner's `type` and `errorType` and no `code`, so a caller branching on `code` reads its absence as a refusal the runner authored and branches on `type` or `errorType` there. Where the platform sends no `error_domain`, as its Lambda-backed routes do not yet, the fallback reads `errorDomain` from the status, so the branch below reads the same whichever decided it:
|
|
180
180
|
|
|
181
181
|
```ts
|
|
182
182
|
import { ApiResponseError } from "@pipelex/sdk";
|
|
@@ -208,7 +208,7 @@ A refusal about a saved method or one of its versions carries one of the platfor
|
|
|
208
208
|
| `method_not_published` | `409` | A bare `method_id`, which names the latest published version, on a run or tooling route, for a method never published. The detail names `mt_…@draft` and publishing. | Publish the method, or address its draft as `mt_…@draft`. |
|
|
209
209
|
| `method_version_not_found` | `404` | `mt_…@<n>`, or `getMethodVersion`, names a version the method never published. An unknown method is `not_found` instead, so the two are told apart by the code. | Pick a version `listMethodVersions` lists. |
|
|
210
210
|
|
|
211
|
-
A malformed version suffix (`@0`, `@03`, `@Draft`, two suffixes) is a `422` `validation_failed` whose `errors` name the field `method_id`; `parseMethodSelector` refuses the same selectors locally with a `RequestArgumentError`, before anything is sent.
|
|
211
|
+
A malformed version suffix (`@0`, `@03`, `@Draft`, two suffixes) is a `422` `validation_failed` whose `errors` name the field `method_id`; `parseMethodSelector` refuses the same selectors locally with a `RequestArgumentError`, before anything is sent. So is any suffix on the run routes' linkage form, a `method_id` beside an inline source, which `execute` and `start` refuse locally the same way.
|
|
212
212
|
|
|
213
213
|
## A validation item — `ValidationErrorItem`
|
|
214
214
|
|
|
@@ -115,7 +115,7 @@ Exactly one per call. The type pins the other two to `never`, so a second select
|
|
|
115
115
|
| --- | --- | --- |
|
|
116
116
|
| `files` | the inline MTHDS closure (`{content, source?}` entries) | nobody — inline |
|
|
117
117
|
| `method_ref` | a published method's address, `github.com/<owner>/<repo>[/<selector>][@<tag>]` | the runner, server-side (pipelex-api >= 0.21.0 fetches the repository at the tag) |
|
|
118
|
-
| `method_id` | a stored method's catalog id (`mt_
|
|
118
|
+
| `method_id` | a stored method's catalog id (`mt_…`, `mt_…@<n>` or `mt_…@draft`) | the hosted platform, which injects the `.mthds` files of the version it names before the runner sees the request |
|
|
119
119
|
|
|
120
120
|
Nothing is expanded client-side: `method_id` here is a **pass-through**, the same rule every other id-taking operation follows. `getMethodClosure` stays available for callers that want the files in hand, but it is no longer a step on the way to preparing inputs.
|
|
121
121
|
|
package/docs/run-results.md
CHANGED
|
@@ -40,7 +40,7 @@ const results = await client.waitForResult(runId, { artifacts: ["working_memory"
|
|
|
40
40
|
|
|
41
41
|
**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`.
|
|
42
42
|
|
|
43
|
-
An empty selection or a name outside the list is a `
|
|
43
|
+
An empty selection or a name outside the list is a `RequestArgumentError` thrown before any request, `input` and not retryable, 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.
|
|
44
44
|
|
|
45
45
|
## `pipeline_run_id` — the durable handle
|
|
46
46
|
|