@pipelex/sdk 0.64.0 → 0.65.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.
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * A method's stored layouts: the layout a producer designed for one pipe of a published version,
3
3
  * which the hosted platform stores beside the method (`storeMethodLayout`,
4
- * `POST /v1/methods/{id}/versions/{n}/layouts`) and hands back on the validate of the method by id
4
+ * `POST /v1/methods/{id}/versions/{n}/layouts`), reads back by the version
5
+ * (`listMethodLayouts`, `GET` of the same route) and hands back on the validate of the method by id
5
6
  * that names `layouts` among its `views` (`PipelexValidationReport.layouts`).
6
7
  *
7
8
  * A layout is a data file: a tree of elements written in the vocabulary of a catalog of
@@ -13,7 +14,8 @@
13
14
  * and the `layouts` token are the hosted plane's.
14
15
  *
15
16
  * The readers here check a layout member by member, as `readProblemItems` checks a verdict's
16
- * items: a validate never loses its verdict, nor its other layouts, to one layout it cannot read.
17
+ * items: neither a validate nor a read of a version's layouts loses its other layouts, nor a
18
+ * validate its verdict, to one layout it cannot read.
17
19
  */
18
20
  /**
19
21
  * How a stored layout was made, as its producer stated it when it wrote the layout. Every member
@@ -36,8 +38,8 @@ export interface LayoutProvenance {
36
38
  repair_rounds: number;
37
39
  }
38
40
  /**
39
- * One stored layout — what `storeMethodLayout` answers, and an entry of
40
- * `PipelexValidationReport.layouts`.
41
+ * One stored layout — what `storeMethodLayout` answers, an entry of `listMethodLayouts`'s `items`,
42
+ * and an entry of `PipelexValidationReport.layouts`.
41
43
  *
42
44
  * Its identity is `tree_digest`, `pipe_ref`, `catalog` and `prompt_hash` within one method: it
43
45
  * belongs to the content it was designed for, never to a version number, so it is served for
@@ -69,6 +71,20 @@ export interface MethodLayout {
69
71
  provenance: LayoutProvenance;
70
72
  /** The moment the write that stored it landed, ISO 8601 in UTC: the one member the platform sets. */
71
73
  stored_at: string;
74
+ /**
75
+ * A written sample of the result the layout was designed over, as one JSON text the platform
76
+ * stores and never reads, so a host can draw a designed result page before anyone has run the
77
+ * method; `null` when none was stored, and from a platform that predates it. Parse it yourself,
78
+ * and treat it as untrusted: nothing but the JSON syntax was checked.
79
+ */
80
+ sample_json: string | null;
81
+ }
82
+ /**
83
+ * The layouts stored for a published version's content — what `listMethodLayouts` answers. `items`
84
+ * is newest first, at most 16, and empty when none is stored.
85
+ */
86
+ export interface MethodLayoutList {
87
+ items: MethodLayout[];
72
88
  }
73
89
  /**
74
90
  * The provenance a write states — `MethodLayoutInput.provenance`. A `null` or omitted optional
@@ -89,7 +105,8 @@ export interface LayoutProvenanceInput {
89
105
  /**
90
106
  * The write — `storeMethodLayout`, `POST /v1/methods/{id}/versions/{n}/layouts`: the stored layout
91
107
  * without `stored_at`. The wire body is closed at both levels, so the client sends these members
92
- * and nothing else; a `MethodLayout` read back can be passed as it is, its `stored_at` left out.
108
+ * and nothing else; a `MethodLayout` read back can be passed as it is, its `stored_at` left out and
109
+ * its `sample_json` sent when it holds one.
93
110
  * The bounds below are the platform's, which refuses a member breaking one with a `422`
94
111
  * `request.invalid` naming it, `provenance.<member>` for one of the provenance's.
95
112
  */
@@ -116,18 +133,31 @@ export interface MethodLayoutInput {
116
133
  jsonl: string;
117
134
  /** How it was made. */
118
135
  provenance: LayoutProvenanceInput;
136
+ /**
137
+ * A written sample of the result the layout was designed over, one JSON text of at most 64 KiB of
138
+ * UTF-8, which the platform refuses if it does not parse. A `null` or omitted sample is not sent,
139
+ * and the write stores none, whatever the layout it replaces held.
140
+ *
141
+ * **Only a written sample belongs here, invented from the description of the result and holding
142
+ * no customer's data, never a run's output.** A layout's readers include the method's runners
143
+ * and, for a public method, other organizations, and the platform never reads the sample, so
144
+ * keeping that rule is the producer's.
145
+ */
146
+ sample_json?: string | null;
119
147
  }
120
148
  /**
121
- * The members the write sends besides `provenance`, every one each time. Checked against
122
- * `MethodLayoutInput` with `satisfies`, so a member the interface gains and this list lacks fails
123
- * the build rather than being dropped from the body without a word.
149
+ * The members the write takes besides `provenance`, `required` ones sent each time and `optional`
150
+ * ones only when given and not `null`. Checked against `MethodLayoutInput` with `satisfies`, so a
151
+ * member the interface gains and this list lacks fails the build rather than being dropped from
152
+ * the body without a word.
124
153
  */
125
154
  export declare const LAYOUT_INPUT_MEMBERS: {
126
- readonly tree_digest: true;
127
- readonly pipe_ref: true;
128
- readonly catalog: true;
129
- readonly prompt_hash: true;
130
- readonly jsonl: true;
155
+ readonly tree_digest: "required";
156
+ readonly pipe_ref: "required";
157
+ readonly catalog: "required";
158
+ readonly prompt_hash: "required";
159
+ readonly jsonl: "required";
160
+ readonly sample_json: "optional";
131
161
  };
132
162
  /**
133
163
  * The members of the write's provenance, `required` ones sent each time and `optional` ones only
@@ -150,15 +180,16 @@ export declare const PROVENANCE_INPUT_MEMBERS: {
150
180
  export declare function methodLayoutFault(value: unknown): string | null;
151
181
  /**
152
182
  * `value` read as a stored layout, or `null` when it does not read as one (`methodLayoutFault`).
153
- * The provenance's `seed` and `style` are kept only when each is a string, and read as `null`
154
- * otherwise, and its `repair_rounds` only when it is a non-negative integer, and read as `0`
155
- * otherwise: the platform's own defaults, so each member is what `LayoutProvenance` declares. The
156
- * rest is returned as it came.
183
+ * The layout's `sample_json` and the provenance's `seed` and `style` are kept only when each is a
184
+ * string, and read as `null` otherwise, and its `repair_rounds` only when it is a non-negative
185
+ * integer, and read as `0` otherwise: the platform's own defaults, so each member is what
186
+ * `MethodLayout` and `LayoutProvenance` declare. The rest is returned as it came.
157
187
  */
158
188
  export declare function readMethodLayout(value: unknown): MethodLayout | null;
159
189
  /**
160
- * A valid report's `layouts` read entry by entry: each entry that reads as a layout
161
- * (`readMethodLayout`), in the answer's order, newest first as the platform sends them, and
162
- * anything else left out. A value that is not an array reads as no layout.
190
+ * A list of layouts read entry by entry, a valid report's `layouts` or `listMethodLayouts`'s
191
+ * `items`: each entry that reads as a layout (`readMethodLayout`), in the answer's order, newest
192
+ * first as the platform sends them, and anything else left out. A value that is not an array reads
193
+ * as no layout.
163
194
  */
164
195
  export declare function readMethodLayouts(value: unknown): MethodLayout[];
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * A method's stored layouts: the layout a producer designed for one pipe of a published version,
3
3
  * which the hosted platform stores beside the method (`storeMethodLayout`,
4
- * `POST /v1/methods/{id}/versions/{n}/layouts`) and hands back on the validate of the method by id
4
+ * `POST /v1/methods/{id}/versions/{n}/layouts`), reads back by the version
5
+ * (`listMethodLayouts`, `GET` of the same route) and hands back on the validate of the method by id
5
6
  * that names `layouts` among its `views` (`PipelexValidationReport.layouts`).
6
7
  *
7
8
  * A layout is a data file: a tree of elements written in the vocabulary of a catalog of
@@ -13,20 +14,23 @@
13
14
  * and the `layouts` token are the hosted plane's.
14
15
  *
15
16
  * The readers here check a layout member by member, as `readProblemItems` checks a verdict's
16
- * items: a validate never loses its verdict, nor its other layouts, to one layout it cannot read.
17
+ * items: neither a validate nor a read of a version's layouts loses its other layouts, nor a
18
+ * validate its verdict, to one layout it cannot read.
17
19
  */
18
20
  import { isPlainObject } from "./records.js";
19
21
  /**
20
- * The members the write sends besides `provenance`, every one each time. Checked against
21
- * `MethodLayoutInput` with `satisfies`, so a member the interface gains and this list lacks fails
22
- * the build rather than being dropped from the body without a word.
22
+ * The members the write takes besides `provenance`, `required` ones sent each time and `optional`
23
+ * ones only when given and not `null`. Checked against `MethodLayoutInput` with `satisfies`, so a
24
+ * member the interface gains and this list lacks fails the build rather than being dropped from
25
+ * the body without a word.
23
26
  */
24
27
  export const LAYOUT_INPUT_MEMBERS = {
25
- tree_digest: true,
26
- pipe_ref: true,
27
- catalog: true,
28
- prompt_hash: true,
29
- jsonl: true,
28
+ tree_digest: "required",
29
+ pipe_ref: "required",
30
+ catalog: "required",
31
+ prompt_hash: "required",
32
+ jsonl: "required",
33
+ sample_json: "optional",
30
34
  };
31
35
  /**
32
36
  * The members of the write's provenance, `required` ones sent each time and `optional` ones only
@@ -76,10 +80,10 @@ export function methodLayoutFault(value) {
76
80
  }
77
81
  /**
78
82
  * `value` read as a stored layout, or `null` when it does not read as one (`methodLayoutFault`).
79
- * The provenance's `seed` and `style` are kept only when each is a string, and read as `null`
80
- * otherwise, and its `repair_rounds` only when it is a non-negative integer, and read as `0`
81
- * otherwise: the platform's own defaults, so each member is what `LayoutProvenance` declares. The
82
- * rest is returned as it came.
83
+ * The layout's `sample_json` and the provenance's `seed` and `style` are kept only when each is a
84
+ * string, and read as `null` otherwise, and its `repair_rounds` only when it is a non-negative
85
+ * integer, and read as `0` otherwise: the platform's own defaults, so each member is what
86
+ * `MethodLayout` and `LayoutProvenance` declare. The rest is returned as it came.
83
87
  */
84
88
  export function readMethodLayout(value) {
85
89
  if (methodLayoutFault(value) !== null)
@@ -88,6 +92,7 @@ export function readMethodLayout(value) {
88
92
  const { seed, style, repair_rounds: rounds } = layout.provenance;
89
93
  return {
90
94
  ...layout,
95
+ sample_json: typeof layout.sample_json === "string" ? layout.sample_json : null,
91
96
  provenance: {
92
97
  ...layout.provenance,
93
98
  seed: typeof seed === "string" ? seed : null,
@@ -97,9 +102,10 @@ export function readMethodLayout(value) {
97
102
  };
98
103
  }
99
104
  /**
100
- * A valid report's `layouts` read entry by entry: each entry that reads as a layout
101
- * (`readMethodLayout`), in the answer's order, newest first as the platform sends them, and
102
- * anything else left out. A value that is not an array reads as no layout.
105
+ * A list of layouts read entry by entry, a valid report's `layouts` or `listMethodLayouts`'s
106
+ * `items`: each entry that reads as a layout (`readMethodLayout`), in the answer's order, newest
107
+ * first as the platform sends them, and anything else left out. A value that is not an array reads
108
+ * as no layout.
103
109
  */
104
110
  export function readMethodLayouts(value) {
105
111
  if (!Array.isArray(value))
@@ -1 +1 @@
1
- {"version":3,"file":"method-layouts.js","sourceRoot":"","sources":["../src/method-layouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA4G7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EAAE,IAAI;IACjB,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,WAAW,EAAE,IAAI;IACjB,KAAK,EAAE,IAAI;CACoE,CAAC;AAElF;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;IACjB,aAAa,EAAE,UAAU;CACsD,CAAC;AAElF,iGAAiG;AACjG,MAAM,qBAAqB,GAAG;IAC5B,aAAa;IACb,UAAU;IACV,SAAS;IACT,aAAa;IACb,OAAO;IACP,WAAW;CACH,CAAC;AAEX,4DAA4D;AAC5D,MAAM,yBAAyB,GAAG,CAAC,UAAU,EAAE,OAAO,CAAU,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,uBAAuB,CAAC;IAC1D,KAAK,MAAM,MAAM,IAAI,qBAAqB,EAAE,CAAC;QAC3C,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,OAAO,WAAW,MAAM,oBAAoB,CAAC;IACtF,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACpC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;QAAE,OAAO,qCAAqC,CAAC;IAC7E,KAAK,MAAM,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC/C,IAAI,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC3C,OAAO,sBAAsB,MAAM,oBAAoB,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,iBAAiB,CAAC,KAAK,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,MAAM,GAAG,KAA0E,CAAC;IAC1F,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;IACjE,OAAO;QACL,GAAG,MAAM;QACT,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;YAC5C,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;YAC/C,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAK,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACpF;KACyB,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,KAAkB,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"method-layouts.js","sourceRoot":"","sources":["../src/method-layouts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAuI7C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW,EAAE,UAAU;IACvB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,UAAU;IACnB,WAAW,EAAE,UAAU;IACvB,KAAK,EAAE,UAAU;IACjB,WAAW,EAAE,UAAU;CAIxB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,UAAU;IACjB,aAAa,EAAE,UAAU;CACsD,CAAC;AAElF,iGAAiG;AACjG,MAAM,qBAAqB,GAAG;IAC5B,aAAa;IACb,UAAU;IACV,SAAS;IACT,aAAa;IACb,OAAO;IACP,WAAW;CACH,CAAC;AAEX,4DAA4D;AAC5D,MAAM,yBAAyB,GAAG,CAAC,UAAU,EAAE,OAAO,CAAU,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,uBAAuB,CAAC;IAC1D,KAAK,MAAM,MAAM,IAAI,qBAAqB,EAAE,CAAC;QAC3C,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,OAAO,WAAW,MAAM,oBAAoB,CAAC;IACtF,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACpC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;QAAE,OAAO,qCAAqC,CAAC;IAC7E,KAAK,MAAM,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC/C,IAAI,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC3C,OAAO,sBAAsB,MAAM,oBAAoB,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,iBAAiB,CAAC,KAAK,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,MAAM,GAAG,KAA0E,CAAC;IAC1F,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;IACjE,OAAO;QACL,GAAG,MAAM;QACT,WAAW,EAAE,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;QAC/E,UAAU,EAAE;YACV,GAAG,MAAM,CAAC,UAAU;YACpB,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;YAC5C,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;YAC/C,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAK,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;SACpF;KACyB,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,KAAkB,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -191,6 +191,13 @@ export interface MethodData {
191
191
  * arrives as its raw string. The list rows (`MethodSummary`) do not carry it.
192
192
  */
193
193
  visibility?: MethodVisibility | (string & {});
194
+ /**
195
+ * The ids of the catalogs whose layouts a builder switched off, which no host draws: it draws the
196
+ * plain page instead, and the layouts are kept. Written whole by `setMethodLayoutsOff`, it acts at
197
+ * once and holds across every publish. Absent from a platform that predates it, which means none.
198
+ * The list rows (`MethodSummary`) do not carry it.
199
+ */
200
+ layouts_off?: string[];
194
201
  }
195
202
  /** Who may see a method — `MethodData.visibility`. */
196
203
  export type MethodVisibility = "internal" | "public";
@@ -255,6 +262,11 @@ export interface PublicMethodDetail {
255
262
  latest_published: MethodVersionSummary;
256
263
  /** `public`: another organization reads a method only while it is public. */
257
264
  visibility: MethodVisibility | (string & {});
265
+ /**
266
+ * The ids of the catalogs whose layouts no host draws, as on `MethodData.layouts_off`: a reader
267
+ * of the method draws the plain page for those. Absent from a platform that predates it.
268
+ */
269
+ layouts_off?: string[];
258
270
  /** The latest published version's tree, one entry per file in tree path order. */
259
271
  files: SavedMethodFile[];
260
272
  }
package/dist/version.d.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  * `User-Agent` without importing the public barrel. Kept in sync with
4
4
  * `package.json` — enforced by `tests/index.test.ts`.
5
5
  */
6
- export declare const SDK_VERSION = "0.64.0";
6
+ export declare const SDK_VERSION = "0.65.0";
package/dist/version.js CHANGED
@@ -3,5 +3,5 @@
3
3
  * `User-Agent` without importing the public barrel. Kept in sync with
4
4
  * `package.json` — enforced by `tests/index.test.ts`.
5
5
  */
6
- export const SDK_VERSION = "0.64.0";
6
+ export const SDK_VERSION = "0.65.0";
7
7
  //# sourceMappingURL=version.js.map
@@ -117,7 +117,7 @@ Flat `src/` (mirrors `mthds-js`'s `runners/api` flatness — the SDK has one cli
117
117
  - `client.ts` — `PipelexApiClient`: the `request()` pipeline (auth, base URL, timeouts/abort, problem-details parsing) and every route. It implements the standard's `MTHDSProtocol<DictPipeOutput>` for every route but `validate`, so the protocol-execution methods stay shaped like the standard: `validate` answers Pipelex's own verdict, `PipelexValidationResult`, because the hosted plane still sends the verdict that predates the protocol's problem items, where the standard's `ValidationResult` lists them.
118
118
  - `models.ts` — Dict-serialized concretes (`DictStuff` / `DictWorkingMemory` / `DictPipeOutput` / `DictRunResultExecute`), the `/v1/validate` surface (`PipelexValidationResult`, whose two arms are declared whole rather than as narrowings of the standard's `ValidationResult`, listing their faults and warnings as the standard's `ProblemItem`, with its `SuggestedFix` and `FixOp`, see [errors.md](./errors.md#a-verdicts-problem-items)), the tools surface (`Diagnostic` / `LintResponse` / `FormatResponse`), and the crate-route request/response models — the shared `CrateRequestBase` / `CrateInvalidReport` vocabulary plus the `/v1/resolve`, `/v1/codegen` and `/v1/pipe-io` shapes built on it, `GeneratedArtifact` among them.
119
119
  - `product-models.ts` — the snake_case wire shapes for the hosted-product management routes (profile, methods catalog, organizations, billing, API keys, onboarding, storage, an organization's files, runs list/detail/update). Each interface models only the fields the product actually consumes — no speculative mirrors.
120
- - `method-layouts.ts` — a method's stored layouts: `MethodLayoutInput` and `LayoutProvenanceInput`, the write `storeMethodLayout` sends, `MethodLayout` and `LayoutProvenance`, what the platform stores, answers and carries on a validate's `layouts`, and the reader both go through, `readMethodLayout` (with `methodLayoutFault`, which names the member an unreadable layout breaks, and `readMethodLayouts`, which reads a report's list entry by entry). It imports the plain-object guard of `records.ts` and nothing else. The Python twin is `pipelex_sdk/method_layout_models.py`. See [method-layouts.md](./method-layouts.md).
120
+ - `method-layouts.ts` — a method's stored layouts: `MethodLayoutInput` and `LayoutProvenanceInput`, the write `storeMethodLayout` sends, `MethodLayout` and `LayoutProvenance`, what the platform stores, answers and carries on a validate's `layouts`, `MethodLayoutList`, what `listMethodLayouts` answers, and the reader they all go through, `readMethodLayout` (with `methodLayoutFault`, which names the member an unreadable layout breaks, and `readMethodLayouts`, which reads a list of layouts entry by entry). It imports the plain-object guard of `records.ts` and nothing else. The Python twin is `pipelex_sdk/method_layout_models.py`. See [method-layouts.md](./method-layouts.md).
121
121
  - `answer-reading.ts` — `readHostedAnswer`, the reading of an answer that is not the route's result as its problem: a problem document as received, and an answer whose body is none, the hosted edge's, a gateway's or a proxy's, by its status, `client.outcome_unknown` for a start or an execute that may have created a run; and `outcomeUnknownProblem`. `ApiResponseError` reads every answer through it. The Python twin is `pipelex_sdk/answer_reading.py`. See [errors.md](./errors.md#an-answer-that-is-no-problem-document).
122
122
  - `transport-reading.ts` — `requestMayHaveLeft`, the **pure** reading of whether a request that got no answer may have left this machine, every failure counting unless it proves nothing was sent (a failure of the connection's set-up). `ApiUnreachableError` applies it on a start or an execute, which the client marks with `mayStartRun`, to read the failure as `client.unreachable` or `client.outcome_unknown`. The Python twin is `pipelex_sdk/transport_reading.py`. See [errors.md](./errors.md#a-run-that-may-have-started--outcome_unknown).
123
123
  - `problem-items.ts` — `readProblemItems`, the reading of a verdict's `errors` and `warnings` as the standard's problem items, member by member, so one malformed member never costs the caller its fault. The Python twin is `pipelex_sdk/problem_items.py`. See [errors.md](./errors.md#a-verdicts-problem-items).
@@ -162,7 +162,7 @@ The hosted catalog/account routes the webapp drives. All ride the same `{base}/v
162
162
  - **Method examples:** `createMethodExample`, `listMethodExamples`, `iterateMethodExamples`, `getMethodExample`, `updateMethodExample`, `recordMethodExampleLatestRun`, `saveAssistantMethodExample`, `deleteMethodExample`, on `/v1/methods/{id}/examples`. An example is a named set of inputs saved on a method, shared across the organization, with an `input_revision` that rises each time its inputs change and the `latest_run_id` of those inputs, which an inputs edit clears. `recordMethodExampleLatestRun` records a run against the revision whose inputs it used and answers a `MethodExampleLatestRunResult` discriminated on `outcome`, `recorded` or `stale`, each arm carrying the `example`: a run that outlasted an edit is a verdict, never thrown, and an answer off the union is one the SDK cannot read; `saveAssistantMethodExample` is the build assistant's save, which writes into the example it names only while that example is still the assistant's (`kept_by_assistant`) at the revision it read, and otherwise creates one, answering a `MethodExampleAssistantSaveResult` discriminated on `outcome`, `kept` or `created`; one helper, `readVerdict`, reads these verdicts and `publishMethod`'s, the example checked once, by the reader every example goes through. Every answer carrying an example is read with `parseExactJson` and every request body written with `stringifyExactJson`, so an integer past `Number.MAX_SAFE_INTEGER` in the inputs reads as a `bigint` and goes back digit for digit, to an edit or as a run's inputs; `3.0` still reads as `3`, and inputs holding one sent back unchanged are an edit for the platform, which compares inputs as canonical JSON. Every example the client hands back, the page rows and the verdict's `example` included, is checked by `readMethodExample` against the fields the Python SDK's model requires, with the strict types it holds them to, an example breaking one being an answer the SDK cannot read. The list is paged oldest first by an opaque cursor, and a page may be short while `nextCursor` is set; `iterateMethodExamples` follows it through the loop `iterateMethods` and `iterateRuns` share, and refuses a method id at the call rather than at the first pull. Every method takes a bare catalog id, and the client refuses an example id that is empty, `.` or `..` or holds a lone surrogate, a create without its name or inputs or whose `run_id` is given but empty, an edit naming neither `name` nor `inputs`, and a latest-run write without a run id or a positive integer revision before sending. See [method-examples.md](./method-examples.md).
163
163
  - **Template catalog:** `listMethodTemplates`, `iterateMethodTemplates`, on `GET /v1/method-templates`, and `listMethodCategories`, on `GET /v1/method-categories`. The public methods of the deployment's templates organization, in the order the platform serves for the `ordering` asked for, filtered by `category`, with the page's `categories` and each card's thumbnails behind short-lived links. `listMethodTemplates` reads the page with its own reader rather than `requestPage`, since its `ordering` and `categories` sit beside `items` and `nextCursor`, and redacts the links of an answer it cannot read; `iterateMethodTemplates` follows the cursor with the same ordering and category. `listMethodCategories` reads the catalog's whole list of categories, which an admin of the platform keeps, in its order. Both check each category with one reader, `methodCategoriesFault`: a string `slug` and `label`, and `labels`, an object of strings by language tag ([public-methods.md](./public-methods.md)).
164
164
  - **Method copies:** `copyMethod`, on `/v1/methods/{id}/copy`. `copyMethod` makes a new, unpublished method in an organization the caller may change methods in, the method's own for a duplicate, holding the original's draft tree, its form inputs and its examples, the stored files they name copied into the destination, and answers a `MethodCopyResult` discriminated on `outcome`: `copied` with the copy as `method` and what was copied, or `refused` with the `references` of a bundle naming storage the destination cannot read or, in a duplicate, a file under the original's run files, which erasing the original would remove. The two arms carry different members, so the verdict is read by the copy itself rather than by `readVerdict`, which reads verdicts whose arms share one: an `outcome` off the union, a `copied` answer whose `method` is not an object and a `refused` one whose `references` is not an array are each an answer the SDK cannot read. Its body is closed, `destination_org_id` with `name` and `expected_draft_updated_at` when given, and its last argument takes an `idempotencyKey`, sent as the `Idempotency-Key` header through the same `requestRaw` option and the same `idempotencyKeyOf` check a start uses. Every method read carries `copied_from`, the original a copy names, `null` on a method created afresh. `MethodErrorCode` names the copy's own codes, `pipelex.org.not_found` and `pipelex.catalog.copy_too_large`, whose `limit` member is typed `MethodCopyLimit`. It takes a bare catalog id. See [method-copy.md](./method-copy.md).
165
- - **Method layouts:** `storeMethodLayout`, on `/v1/methods/{id}/versions/{n}/layouts`, and the `layouts` view of `validate`. A layout is a data file a producer designed for one pipe of a published version, which the platform stores keyed by the content it was designed for, `tree_digest`, `pipe_ref`, `catalog` and `prompt_hash`, a write of the same identity replacing it, and carries on every validate by `method_id` that names `layouts` and resolves the same tree. The write takes a bare catalog id and a positive integer version, refuses a layout or a provenance that is not an object before sending, and sends the closed body alone, its members listed once in `method-layouts.ts` (`LAYOUT_INPUT_MEMBERS`, `PROVENANCE_INPUT_MEMBERS`) and held to the input interfaces by `satisfies`, each optional provenance member that is `null` or omitted left out; its last argument takes an `idempotencyKey` (`MethodLayoutWriteOptions`), sent as the `Idempotency-Key` header through the same `idempotencyKeyOf` check a start and a copy use, since a write sent again without one runs again, restamping the layout and applying the bound again; the platform's refusals (`422` `request.invalid` naming the member, `tree_digest` among them for a tree that is not the version's, `403` `auth.forbidden` for a runner, `404` `pipelex.catalog.not_found` naming the method or the version, `409` `pipelex.catalog.being_deleted`) are `ApiResponseError`s. One reader in `method-layouts.ts`, `readMethodLayout`, holds the write's answer and each entry of a report's `layouts` to the same rule, the six identity and payload members strings and the provenance an object with a string `producer` and `model`, its `seed` and `style` read as `null` and its `repair_rounds` as `0` when they do not fit; an answer breaking it is one the SDK cannot read, and an entry breaking it is left out of the report, a list left with none removed, so `layouts` is absent or holds at least one layout. See [method-layouts.md](./method-layouts.md).
165
+ - **Method layouts:** `storeMethodLayout` and `listMethodLayouts`, on `/v1/methods/{id}/versions/{n}/layouts`, `setMethodLayoutsOff`, on `/v1/methods/{id}/layouts-off`, and the `layouts` view of `validate`. A layout is a data file a producer designed for one pipe of a published version, which the platform stores keyed by the content it was designed for, `tree_digest`, `pipe_ref`, `catalog` and `prompt_hash`, a write of the same identity replacing it, and carries on every validate by `method_id` that names `layouts` and resolves the same tree. The write takes a bare catalog id and a positive integer version, refuses a layout or a provenance that is not an object before sending, and sends the closed body alone, its members listed once in `method-layouts.ts` (`LAYOUT_INPUT_MEMBERS`, `PROVENANCE_INPUT_MEMBERS`) and held to the input interfaces by `satisfies`, `sample_json` and each optional provenance member that is `null` or omitted left out; its last argument takes an `idempotencyKey` (`MethodLayoutWriteOptions`), sent as the `Idempotency-Key` header through the same `idempotencyKeyOf` check a start and a copy use, since a write sent again without one runs again, restamping the layout and applying the bound again; the platform's refusals (`422` `request.invalid` naming the member, `tree_digest` among them for a tree that is not the version's, `403` `auth.forbidden` for a runner, `404` `pipelex.catalog.not_found` naming the method or the version, `409` `pipelex.catalog.being_deleted`) are `ApiResponseError`s. One reader in `method-layouts.ts`, `readMethodLayout`, holds the write's answer and each entry of a report's `layouts` to the same rule, the six identity and payload members strings and the provenance an object with a string `producer` and `model`, its `seed` and `style` read as `null` and its `repair_rounds` as `0` when they do not fit; an answer breaking it is one the SDK cannot read, and an entry breaking it is left out of the report, a list left with none removed, so `layouts` is absent or holds at least one layout. `listMethodLayouts` reads the same list with no dry run, its `items` read entry by entry by that rule, and `setMethodLayoutsOff` writes the whole list of switched-off catalogs, an array or a `RequestArgumentError` before sending, its idempotency key sent as the write's is. See [method-layouts.md](./method-layouts.md).
166
166
  - **Organizations:** `listMemberships`, `createOrganization`, `renameOrganization` (`PATCH`). Each membership carries the caller's `role_in_org`, an `OrgRole` (`admin`, `member` or `runner`) read open: a role a later platform adds arrives as its raw string, so a `switch` over it says what an unknown role does. The role is for display; what it may do is the platform's to decide, and a call refused to the caller's role is an `ApiResponseError`. The org "switch" is a WorkOS-session op (`/api/active-org`), not a `/v1` route — out of SDK scope.
167
167
  - **Organization branding:** `getBranding` (`GET /v1/branding`, any role, web session or API key) and `updateOrganizationBranding` (`PATCH /v1/organizations/{org_id}/branding`, a write by the `admin` or the `member` role, never a `runner`) answer the same `OrganizationBranding`: the organization's name, its light and dark colour sets (`BrandingColors`), its square and wide logos (`LogoDescriptor`), its app `style` and `typeface`, and its read-only `white_label` entitlement, the last three read as `null`, `null` and `false` from a platform that predates them. The write's `OrganizationBrandingUpdate` sets a key given a value, clears a key given `null` and keeps a key left out; a refused field is named by its `location.field`, a colour by its dotted key, a logo by its slot in `ApiResponseError.errors` with a `LogoRefusalCode` when the platform measured it. See [organization-branding.md](./organization-branding.md).
168
168
  - **Caller webhooks:** `listRunWebhookDeliveries`, `getRunWebhookDelivery` and `replayRunWebhookDelivery`, on `/v1/runs/{id}/webhook-deliveries`, `/v1/runs/{id}/webhook-deliveries/{delivery_id}` and its `/replay`, read a run's delivery log and send a settled delivery again, any member by web session or API key, the replay taking an `idempotencyKey` under which the platform stores its answer; `getWebhookSecret`, on `GET /v1/organizations/{org_id}/webhook-secret`, and `rotateWebhookSecret`, on `POST /v1/organizations/{org_id}/webhook-secret/rotate`, read and rotate the organization's signing secret, an admin's routes from a web session only, the rotation taking an `idempotencyKey` the platform never replays. See [webhooks.md](./webhooks.md).
package/docs/errors.md CHANGED
@@ -96,7 +96,7 @@ What the hosted API answers a start sent under a key:
96
96
 
97
97
  **A copy takes a key too.** `copyMethod` sends an `idempotencyKey` the same way, held to the same rule, and the hosted API keeps it for the same 24 hours, scoped to the caller and the method's organization. A copy binds no run, so its answers under a key differ from a start's: [method-copy.md](./method-copy.md#retrying-a-copy--idempotencykey) gives them.
98
98
 
99
- **And a layout write.** `storeMethodLayout` sends an `idempotencyKey` the same way, held to the same rule. A write sent again without one runs again, restamping the layout and applying the bound of layouts a content keeps again, so a write whose answer was lost is sent again under the key it was first sent with, which answers it as the first write was answered: [method-layouts.md](./method-layouts.md#storing-a-layout) gives the answers.
99
+ **And a layout write.** `storeMethodLayout` sends an `idempotencyKey` the same way, held to the same rule. A write sent again without one runs again, restamping the layout and applying the bound of layouts a content keeps again, so a write whose answer was lost is sent again under the key it was first sent with, which answers it as the first write was answered: [method-layouts.md](./method-layouts.md#storing-a-layout) gives the answers. `setMethodLayoutsOff` takes a key by the same rule, since a write of the whole list sent again undoes a switch that landed in between.
100
100
 
101
101
  **So do a secret rotation and a delivery replay.** `rotateWebhookSecret` and `replayRunWebhookDelivery` send an `idempotencyKey` the same way, held to the same rule. A rotation's answer carries a secret, so the platform never replays it, while a replay's stored answer is given again: [webhooks.md](./webhooks.md) gives both.
102
102
 
@@ -1,8 +1,8 @@
1
1
  # A method's stored layouts
2
2
 
3
- A **layout** is a data file a producer designed for one pipe of a method: a tree of elements written in the vocabulary of a catalog of components, every value bound to a path in the host's form state, carrying no field descriptions and no data of its own. A host renders it over the input-form descriptor the same method's validate projects, and renders the plain form instead whenever it cannot. The hosted platform stores layouts beside a method's published versions and hands them back on the validate a host already makes, so a method laid out once opens with its layout for everyone who opens it. It never produces a layout, never parses one and never judges one against a catalog or a descriptor: that is the producer's work before the write and the host's before it renders.
3
+ A **layout** is a data file a producer designed for one pipe of a method: a tree of elements written in the vocabulary of a catalog of components, every value bound to a path in the host's form state, carrying no field descriptions and no data of its own. A host renders it over the input-form descriptor the same method's validate projects, and renders the plain form instead whenever it cannot. The hosted platform stores layouts beside a method's published versions and hands them back, on a direct read by the version or on a validate of the method by id, so a method laid out once opens with its layout for everyone who opens it. It never produces a layout, never parses one and never judges one against a catalog or a descriptor: that is the producer's work before the write and the host's before it renders.
4
4
 
5
- The client reaches the write on the hosted API's `POST /v1/methods/{method_id}/versions/{version}/layouts` and the read on `POST /v1/validate`, under the `layouts` view. The types are in `src/method-layouts.ts`, exported from the package's root: `MethodLayoutInput` and `LayoutProvenanceInput` for the write, `MethodLayout` and `LayoutProvenance` for what is stored. The storage and the `layouts` token are a Pipelex hosted feature; the shapes are stated brand-neutrally, snake_case with no `pipelex_` prefix, as the input-form descriptor they are rendered over is. The conformance spec `pipelex-hosted-method-layouts.md`, in the workspace's `conformance` repository, states the contract.
5
+ The client reaches the write on the hosted API's `POST /v1/methods/{method_id}/versions/{version}/layouts`, the direct read on `GET` of the same route, the read through `POST /v1/validate` under the `layouts` view, and the off switch on `PUT /v1/methods/{method_id}/layouts-off`. The types are in `src/method-layouts.ts`, exported from the package's root: `MethodLayoutInput` and `LayoutProvenanceInput` for the write, `MethodLayout` and `LayoutProvenance` for what is stored, and `MethodLayoutList` for the direct read. The storage and the `layouts` token are a Pipelex hosted feature; the shapes are stated brand-neutrally, snake_case with no `pipelex_` prefix, as the input-form descriptor they are rendered over is. The conformance spec `pipelex-hosted-method-layouts.md`, in the workspace's `conformance` repository, states the contract.
6
6
 
7
7
  ```ts
8
8
  import { PipelexApiClient } from "@pipelex/sdk";
@@ -54,6 +54,7 @@ if (report.is_valid) {
54
54
  | `jsonl` | The layout itself, as the producer's model emitted it: JSON patch lines, one per line, carried as one string exactly as written. |
55
55
  | `provenance` | How it was made: `producer`, `model`, `seed`, `style` and `repair_rounds` (below). |
56
56
  | `stored_at` | The moment the write landed, ISO 8601 in UTC. The one member the platform sets, absent from the write. |
57
+ | `sample_json` | A written sample of the result the layout was designed over, one JSON text, or `null` when none was stored (see [The written sample](#the-written-sample)). |
57
58
 
58
59
  | `provenance` member | Meaning |
59
60
  |---|---|
@@ -63,7 +64,7 @@ if (report.is_valid) {
63
64
  | `style` | The id of the app style the layout was designed under, such as `editorial`, or `null` when it was designed under none. The platform holds it to the shape `^[a-z0-9-]{1,32}$` and never to a list of styles, so a host reads an id it does not know as no style. |
64
65
  | `repair_rounds` | How many repair rounds the producer ran before the layout validated against its catalog. |
65
66
 
66
- **A layout belongs to the content it was designed for, never to a version number.** Its identity is `tree_digest`, `pipe_ref`, `catalog` and `prompt_hash` within one method, and it names no method and no version. It is written against a published version, and served for whatever selector of that method resolves the same tree: the version it was written against, a later version that holds the same tree, or the draft while it holds it. The same tree saved as another method carries none of it, and a copy of a method takes no layout.
67
+ **A layout belongs to the content it was designed for, never to a version number.** Its identity is `tree_digest`, `pipe_ref`, `catalog` and `prompt_hash` within one method, and it names no method and no version. It is written against a published version, and served for whatever selector of that method resolves the same tree: the version it was written against, a later version that holds the same tree, or the draft while it holds it. A publish that writes a new version also carries the previous version's layouts forward, each copied under the new tree as it stood, so a design follows the method; a host's checks decide whether one still fits. The same tree saved as another method carries none of it, and a copy of a method takes no layout.
67
68
 
68
69
  ## Storing a layout
69
70
 
@@ -73,11 +74,11 @@ if (report.is_valid) {
73
74
 
74
75
  It takes a bare catalog id, as every method route does, and refuses a suffixed one (`mt_…@3`) with a `RequestArgumentError` before anything is sent; `version` is the number of the published version the layout was designed for, and a value that is not a positive integer is refused the same way.
75
76
 
76
- **The body is closed at both levels.** The client sends `tree_digest`, `pipe_ref`, `catalog`, `prompt_hash`, `jsonl` and `provenance` with its `producer` and `model`, and `seed`, `style` and `repair_rounds` when each is given and not `null`, and nothing else. A layout read back can be passed as it is: its `stored_at` is left out. A layout or a provenance that is not an object is refused with a `RequestArgumentError` before any request; every other member is sent as given, and the platform holds it to its shape.
77
+ **The body is closed at both levels.** The client sends `tree_digest`, `pipe_ref`, `catalog`, `prompt_hash`, `jsonl` and `provenance` with its `producer` and `model`, and `sample_json` and the provenance's `seed`, `style` and `repair_rounds` when each is given and not `null`, and nothing else. A layout read back can be passed as it is: its `stored_at` is left out. A layout or a provenance that is not an object is refused with a `RequestArgumentError` before any request; every other member is sent as given, and the platform holds it to its shape.
77
78
 
78
79
  **`tree_digest` must be the tree the version holds**, its `MethodVersionSummary.tree_digest`, which `getMethodVersion` and `listMethodVersions` read: a producer designs over the descriptor of the version it was handed, so a layout stating another tree describes content the version does not hold, and is refused.
79
80
 
80
- **A write of the same identity replaces the layout.** The answer is the same `200` whether the write stored a new layout or replaced one, and the replaced layout is carried no more.
81
+ **A write of the same identity replaces the layout**, its sample included, so a write that sends no `sample_json` stores none. The answer is the same `200` whether the write stored a new layout or replaced one, and the replaced layout is carried no more.
81
82
 
82
83
  **A write is sent again under its idempotency key.** `options.idempotencyKey` (`MethodLayoutWriteOptions`) is sent as the `Idempotency-Key` header, and nothing is sent when it is absent or `null`. Under the same key the hosted API answers a retry with the first write's stored answer and runs nothing, so a write whose answer was lost, on a client timeout for instance, is sent again unchanged under the key it was first sent with. Without a key the write runs again: it stamps the layout with a new `stored_at`, which moves it ahead of every layout stored since in the newest-first order, and applies the bound below again, so when another producer stored a newer prompt of the same pipe and catalog meanwhile, the resent layout can come back ahead of it and, at the bound, that newer layout can be the one removed. Generate one key per layout to store, a `crypto.randomUUID()` for instance. The write's `200` and its `4xx` refusals are stored under the key alike; a `5xx` and a refusal for its timing (a `408`, `425` or `429`) are not, so the same key sends the write afresh, and neither are the key's own `409` answers below, so a retry after `request.idempotency_key_in_use` runs as the key's first request would. A key is 1 to 255 visible ASCII characters, and anything else is a `RequestArgumentError` before any request.
83
84
 
@@ -85,13 +86,17 @@ It takes a bare catalog id, as every method route does, and refuses a suffixed o
85
86
 
86
87
  **Who may write.** The write changes the method, so it takes the roles that change methods: an `admin` or a `member` of the method's organization. A `runner` is refused.
87
88
 
89
+ ## The written sample
90
+
91
+ A designed result page needs something to draw before anyone has run the method, so a layout may carry a sample of its result: `sample_json`, one JSON text of at most 64 KiB of UTF-8, which the platform stores and never reads, refusing it on write when it does not parse. **Only a written sample belongs here, invented from the description of the result and holding no customer's data, never a run's output.** A layout's readers include the method's runners and, for a public method, other organizations, and since the platform never reads the sample, keeping that rule is the producer's. The client reads a `sample_json` that is missing or not a string as `null`, and hands the text back as it is: a host parses it and checks it itself.
92
+
88
93
  ## The refusals
89
94
 
90
95
  Each is an `ApiResponseError` carrying the platform's problem, and none stores anything. Branch on its `code`, never on the status.
91
96
 
92
97
  | Status | `code` | When |
93
98
  |---|---|---|
94
- | `422` | `request.invalid` | A member breaking its shape or bound, named in the problem's `params.field` and `location.field`, `provenance.<member>` for one of the provenance's: a missing member, a `tree_digest` that is not `sha256:` and 64 lowercase hexadecimal characters, a `pipe_ref` that is not a dotted reference or is over 256 characters, a `catalog` or `producer` that is not a slug, a `prompt_hash` that is not 12 to 64 lowercase hexadecimal digits, an empty `jsonl`, one over 128 KiB of UTF-8 or one holding a raw control character other than the tab, the line feed and the carriage return, a `model` that is empty, over 128 characters or holds a control character, a `seed` over 4,000 characters, a `style` off its shape, a `repair_rounds` outside 0 to 100, and a lone UTF-16 surrogate in `jsonl`, `model` or `seed`. |
99
+ | `422` | `request.invalid` | A member breaking its shape or bound, named in the problem's `params.field` and `location.field`, `provenance.<member>` for one of the provenance's: a missing member, a `tree_digest` that is not `sha256:` and 64 lowercase hexadecimal characters, a `pipe_ref` that is not a dotted reference or is over 256 characters, a `catalog` or `producer` that is not a slug, a `prompt_hash` that is not 12 to 64 lowercase hexadecimal digits, an empty `jsonl`, one over 128 KiB of UTF-8 or one holding a raw control character other than the tab, the line feed and the carriage return, a `model` that is empty, over 128 characters or holds a control character, a `seed` over 4,000 characters, a `style` off its shape, a `repair_rounds` outside 0 to 100, a `sample_json` over 64 KiB of UTF-8 or that is no JSON text, and a lone UTF-16 surrogate in `jsonl`, `model`, `seed` or `sample_json`. |
95
100
  | `422` | `request.invalid` naming `tree_digest` | `tree_digest` is not the digest of the tree the version holds. |
96
101
  | `403` | `auth.forbidden` | A `runner`, or a caller with no recognised role; its `params.requirement` is `member`. |
97
102
  | `404` | `pipelex.catalog.not_found` | No such method in the caller's organization, another organization's included, its `params.resource` `method`; or a version the method never published, its `params.resource` `version`. |
@@ -102,9 +107,39 @@ Each is an `ApiResponseError` carrying the platform's problem, and none stores a
102
107
 
103
108
  An answer that does not read as a layout, one whose `tree_digest`, `pipe_ref`, `catalog`, `prompt_hash`, `jsonl` or `stored_at` is not a string, or whose `provenance` is not an object with a string `producer` and `model`, is an answer the SDK cannot read, thrown as an `ApiResponseError` coded `client.response_unreadable` whose message names the member.
104
109
 
110
+ ## Reading a version's layouts
111
+
112
+ | Method | Route | Answer |
113
+ |---|---|---|
114
+ | `listMethodLayouts(methodId, version, options?)` | `GET /v1/methods/{id}/versions/{n}/layouts` | A `MethodLayoutList`, whose `items` are the layouts stored for the version's content, newest first, at most 16, empty when none is. |
115
+
116
+ This is what a host calls when it opens a method's page. It touches only the platform's database and calls no runner, where the `layouts` view below dry-runs every pipe of the method to return the same list. It takes a bare catalog id and a positive integer version, each refused with a `RequestArgumentError` before anything is sent, and `options.signal` cancels the read, for a page that can do without its layouts. A `runner` reads what it is shown, another organization's public method answers the layouts its builders stored, and the answer ignores `layouts_off`, which is the host's to honour.
117
+
118
+ Its refusals are `ApiResponseError`s: `404` `pipelex.catalog.not_found` for an unknown method, another organization's internal one (`params.resource` `method`) and a version never published (`params.resource` `version`); `409` `pipelex.catalog.being_deleted` during the erasure of the caller's own method; `500` `runtime.unexpected` for a version stored before methods were trees. `items` is read entry by entry, by the rule below, so an entry that does not read as a layout is left out; an answer whose `items` is not an array is one the SDK cannot read.
119
+
120
+ ```ts
121
+ const { items } = await client.listMethodLayouts("mt_abc123", 3, {
122
+ signal: AbortSignal.timeout(5000),
123
+ });
124
+ ```
125
+
126
+ ## Switching a page's design off
127
+
128
+ A builder can turn a page's design off and on, per catalog, without losing it. The state is `layouts_off`, the catalog slugs whose layouts no host draws, read on `MethodData`, `MethodDetail` and `PublicMethodDetail` and absent from a platform that predates it, which means none.
129
+
130
+ | Method | Route | Answer |
131
+ |---|---|---|
132
+ | `setMethodLayoutsOff(methodId, catalogs, options?)` | `PUT /v1/methods/{id}/layouts-off` | The method, its `layouts_off` the list as held. |
133
+
134
+ `catalogs` is the whole list and replaces the one held, so changing one catalog means reading `layouts_off` and writing the new list; an empty list switches every design on. The switch acts at once with no publish and holds across every publish, and a layout switched off is kept: `listMethodLayouts` and the `layouts` view still answer it, and the host draws the plain page. Like a rename, the write never moves the draft token, so the `updated_at` a caller holds stays valid.
135
+
136
+ **The last write to land is the one held.** A write sent again without a key writes its list again, and so undoes a switch that landed in between. `options.idempotencyKey` (`MethodLayoutsOffOptions`) is sent as the `Idempotency-Key` header, so a write whose answer was lost is sent again under its key and answered as the first was, by the rule [a layout write](#storing-a-layout) follows.
137
+
138
+ A `catalogs` that is not an array is a `RequestArgumentError` before any request, and its entries are sent as given. The route's body is closed, and the platform answers: `422` `request.invalid` for more than 8 catalogs, a catalog named twice or one that is not a slug; `403` `auth.forbidden` for a `runner`; `404` `pipelex.catalog.not_found` for an unknown method or another organization's, a public one included; `409` `pipelex.catalog.being_deleted` during the erasure; and `413` `request.too_large` for a list that would leave the method too large to publish, which a list that does not grow never is, so switching a design back on is always reachable.
139
+
105
140
  ## Reading the layouts: the `layouts` view
106
141
 
107
- A host reads a method's layouts on the validate it makes to read the method's input form. A `validate` naming a stored method by `method_id` (`mt_…`, `mt_…@<n>` or `mt_…@draft`) and naming `layouts` among its `views` is answered, on the valid report, with `layouts`: every layout stored for the tree the selector resolved, newest first by `stored_at`, at most 16. Ask for `views: ["input_form", "layouts"]` to receive the descriptor and the layouts over it in one answer. `ValidateView` types the tokens this SDK knows, `input_form`, `output_form` and `layouts`, and `ValidateOptions.views` still takes any other token as its raw string.
142
+ A host that is already validating the method can read its layouts on the same call, at the cost of the validate's dry run. A `validate` naming a stored method by `method_id` (`mt_…`, `mt_…@<n>` or `mt_…@draft`) and naming `layouts` among its `views` is answered, on the valid report, with `layouts`: every layout stored for the tree the selector resolved, newest first by `stored_at`, at most 16. Ask for `views: ["input_form", "layouts"]` to receive the descriptor and the layouts over it in one answer. `ValidateView` types the tokens this SDK knows, `input_form`, `output_form` and `layouts`, and `ValidateOptions.views` still takes any other token as its raw string.
108
143
 
109
144
  The token rides the `views` list with that list's mechanics: the client sends it verbatim and only when asked, a runner that does not know it ignores it, and it never causes a `422`. The platform forwards `views` as sent and adds the member to the runner's answer.
110
145
 
@@ -116,9 +151,9 @@ The token rides the `views` list with that list's mechanics: the client sends it
116
151
  - no layout is stored for the resolved tree;
117
152
  - the platform could not read the stored layouts, which costs the validate nothing else.
118
153
 
119
- A host therefore never reads an empty array. Publishing a version with another tree leaves the layouts of the old tree where they were: the bare id, now resolving the new tree, carries none of them, and the old version named by its number still carries them all. Another organization's public method carries the layouts its holder's builders stored.
154
+ A host therefore never reads an empty array here. Publishing a version with another tree leaves the layouts of the old tree where they were, and the old version named by its number still carries them all; the new tree carries the copies the publish made of them. Another organization's public method carries the layouts its holder's builders stored.
120
155
 
121
- **The client reads `layouts` entry by entry**, as it reads a verdict's problem items, so one layout it cannot read never costs the caller the verdict or the other layouts: an entry that does not read as a layout, by the rule the write's answer is held to, is left out, and a list left with none is removed. In each entry, a provenance `seed` or `style` that is missing or not a string reads as `null`, and a `repair_rounds` that is missing or not a non-negative integer reads as `0`, the platform's own defaults; the write's answer is read the same way.
156
+ **The client reads `layouts` entry by entry**, as it reads a verdict's problem items, so one layout it cannot read never costs the caller the verdict or the other layouts: an entry that does not read as a layout, by the rule the write's answer is held to, is left out, and a list left with none is removed. In each entry, a `sample_json` or a provenance `seed` or `style` that is missing or not a string reads as `null`, and a `repair_rounds` that is missing or not a non-negative integer reads as `0`, the platform's own defaults; the write's answer and the direct read's entries are read the same way.
122
157
 
123
158
  **Discovery.** `GET /v1/version` lists `method_layouts` among its `extensions` once the platform stores layouts and carries the view. Without it, a validate answering no `layouts` cannot tell a method nobody laid out from a platform that ignores the token, so a host that does not find it offers no layout to produce, since the write would be refused, and renders the plain form. The SDK types no member for it: read it off `version()`, whose answer keeps every extension member as the server sent it.
124
159
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipelex/sdk",
3
- "version": "0.64.0",
3
+ "version": "0.65.0",
4
4
  "description": "TypeScript SDK for the Pipelex hosted API — execute methods, manage runs, and call the product surface.",
5
5
  "license": "MIT",
6
6
  "repository": {