@loomwork/ui-hydration 0.0.0-stage → 0.1.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.
Files changed (179) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +398 -2
  4. package/dist/cache.d.ts +71 -0
  5. package/dist/cache.d.ts.map +1 -0
  6. package/dist/cache.js +157 -0
  7. package/dist/cache.js.map +1 -0
  8. package/dist/chatSource.d.ts +105 -0
  9. package/dist/chatSource.d.ts.map +1 -0
  10. package/dist/chatSource.js +259 -0
  11. package/dist/chatSource.js.map +1 -0
  12. package/dist/client.d.ts +17 -0
  13. package/dist/client.d.ts.map +1 -0
  14. package/dist/client.js +36 -0
  15. package/dist/client.js.map +1 -0
  16. package/dist/contentRefs.d.ts +78 -0
  17. package/dist/contentRefs.d.ts.map +1 -0
  18. package/dist/contentRefs.js +129 -0
  19. package/dist/contentRefs.js.map +1 -0
  20. package/dist/controller.d.ts +228 -0
  21. package/dist/controller.d.ts.map +1 -0
  22. package/dist/controller.js +454 -0
  23. package/dist/controller.js.map +1 -0
  24. package/dist/dataProvider.d.ts +53 -0
  25. package/dist/dataProvider.d.ts.map +1 -0
  26. package/dist/dataProvider.js +77 -0
  27. package/dist/dataProvider.js.map +1 -0
  28. package/dist/esm/cache.js +151 -0
  29. package/dist/esm/cache.js.map +1 -0
  30. package/dist/esm/chatSource.js +254 -0
  31. package/dist/esm/chatSource.js.map +1 -0
  32. package/dist/esm/client.js +15 -0
  33. package/dist/esm/client.js.map +1 -0
  34. package/dist/esm/contentRefs.js +119 -0
  35. package/dist/esm/contentRefs.js.map +1 -0
  36. package/dist/esm/controller.js +449 -0
  37. package/dist/esm/controller.js.map +1 -0
  38. package/dist/esm/dataProvider.js +72 -0
  39. package/dist/esm/dataProvider.js.map +1 -0
  40. package/dist/esm/index.js +15 -0
  41. package/dist/esm/index.js.map +1 -0
  42. package/dist/esm/invoker.js +2 -0
  43. package/dist/esm/invoker.js.map +1 -0
  44. package/dist/esm/invokers.js +310 -0
  45. package/dist/esm/invokers.js.map +1 -0
  46. package/dist/esm/loomEffectProvider.js +96 -0
  47. package/dist/esm/loomEffectProvider.js.map +1 -0
  48. package/dist/esm/params.js +207 -0
  49. package/dist/esm/params.js.map +1 -0
  50. package/dist/esm/path.js +24 -0
  51. package/dist/esm/path.js.map +1 -0
  52. package/dist/esm/plan.js +190 -0
  53. package/dist/esm/plan.js.map +1 -0
  54. package/dist/esm/projection.js +230 -0
  55. package/dist/esm/projection.js.map +1 -0
  56. package/dist/esm/provider.js +416 -0
  57. package/dist/esm/provider.js.map +1 -0
  58. package/dist/esm/repair.js +53 -0
  59. package/dist/esm/repair.js.map +1 -0
  60. package/dist/esm/reshape.js +156 -0
  61. package/dist/esm/reshape.js.map +1 -0
  62. package/dist/esm/restricted.js +54 -0
  63. package/dist/esm/restricted.js.map +1 -0
  64. package/dist/esm/scheduler.js +247 -0
  65. package/dist/esm/scheduler.js.map +1 -0
  66. package/dist/esm/select.js +18 -0
  67. package/dist/esm/select.js.map +1 -0
  68. package/dist/esm/shape.js +34 -0
  69. package/dist/esm/shape.js.map +1 -0
  70. package/dist/esm/split/client.js +309 -0
  71. package/dist/esm/split/client.js.map +1 -0
  72. package/dist/esm/split/index.js +3 -0
  73. package/dist/esm/split/index.js.map +1 -0
  74. package/dist/esm/split/server.js +488 -0
  75. package/dist/esm/split/server.js.map +1 -0
  76. package/dist/esm/split/shared.js +13 -0
  77. package/dist/esm/split/shared.js.map +1 -0
  78. package/dist/index.d.ts +29 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +63 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/invoker.d.ts +10 -0
  83. package/dist/invoker.d.ts.map +1 -0
  84. package/dist/invoker.js +3 -0
  85. package/dist/invoker.js.map +1 -0
  86. package/dist/invokers.d.ts +36 -0
  87. package/dist/invokers.d.ts.map +1 -0
  88. package/dist/invokers.js +315 -0
  89. package/dist/invokers.js.map +1 -0
  90. package/dist/loomEffectProvider.d.ts +67 -0
  91. package/dist/loomEffectProvider.d.ts.map +1 -0
  92. package/dist/loomEffectProvider.js +101 -0
  93. package/dist/loomEffectProvider.js.map +1 -0
  94. package/dist/params.d.ts +103 -0
  95. package/dist/params.d.ts.map +1 -0
  96. package/dist/params.js +221 -0
  97. package/dist/params.js.map +1 -0
  98. package/dist/path.d.ts +12 -0
  99. package/dist/path.d.ts.map +1 -0
  100. package/dist/path.js +28 -0
  101. package/dist/path.js.map +1 -0
  102. package/dist/plan.d.ts +56 -0
  103. package/dist/plan.d.ts.map +1 -0
  104. package/dist/plan.js +199 -0
  105. package/dist/plan.js.map +1 -0
  106. package/dist/projection.d.ts +122 -0
  107. package/dist/projection.d.ts.map +1 -0
  108. package/dist/projection.js +238 -0
  109. package/dist/projection.js.map +1 -0
  110. package/dist/provider.d.ts +152 -0
  111. package/dist/provider.d.ts.map +1 -0
  112. package/dist/provider.js +421 -0
  113. package/dist/provider.js.map +1 -0
  114. package/dist/repair.d.ts +18 -0
  115. package/dist/repair.d.ts.map +1 -0
  116. package/dist/repair.js +57 -0
  117. package/dist/repair.js.map +1 -0
  118. package/dist/reshape.d.ts +32 -0
  119. package/dist/reshape.d.ts.map +1 -0
  120. package/dist/reshape.js +164 -0
  121. package/dist/reshape.js.map +1 -0
  122. package/dist/restricted.d.ts +21 -0
  123. package/dist/restricted.d.ts.map +1 -0
  124. package/dist/restricted.js +61 -0
  125. package/dist/restricted.js.map +1 -0
  126. package/dist/scheduler.d.ts +82 -0
  127. package/dist/scheduler.d.ts.map +1 -0
  128. package/dist/scheduler.js +254 -0
  129. package/dist/scheduler.js.map +1 -0
  130. package/dist/select.d.ts +34 -0
  131. package/dist/select.d.ts.map +1 -0
  132. package/dist/select.js +21 -0
  133. package/dist/select.js.map +1 -0
  134. package/dist/shape.d.ts +3 -0
  135. package/dist/shape.d.ts.map +1 -0
  136. package/dist/shape.js +37 -0
  137. package/dist/shape.js.map +1 -0
  138. package/dist/split/client.d.ts +132 -0
  139. package/dist/split/client.d.ts.map +1 -0
  140. package/dist/split/client.js +313 -0
  141. package/dist/split/client.js.map +1 -0
  142. package/dist/split/index.d.ts +5 -0
  143. package/dist/split/index.d.ts.map +1 -0
  144. package/dist/split/index.js +14 -0
  145. package/dist/split/index.js.map +1 -0
  146. package/dist/split/server.d.ts +160 -0
  147. package/dist/split/server.d.ts.map +1 -0
  148. package/dist/split/server.js +496 -0
  149. package/dist/split/server.js.map +1 -0
  150. package/dist/split/shared.d.ts +6 -0
  151. package/dist/split/shared.d.ts.map +1 -0
  152. package/dist/split/shared.js +19 -0
  153. package/dist/split/shared.js.map +1 -0
  154. package/package.json +77 -3
  155. package/src/cache.ts +211 -0
  156. package/src/chatSource.ts +374 -0
  157. package/src/client.ts +46 -0
  158. package/src/contentRefs.ts +195 -0
  159. package/src/controller.ts +708 -0
  160. package/src/dataProvider.ts +141 -0
  161. package/src/index.ts +86 -0
  162. package/src/invoker.ts +14 -0
  163. package/src/invokers.ts +348 -0
  164. package/src/loomEffectProvider.ts +136 -0
  165. package/src/params.ts +314 -0
  166. package/src/path.ts +26 -0
  167. package/src/plan.ts +197 -0
  168. package/src/projection.ts +297 -0
  169. package/src/provider.ts +657 -0
  170. package/src/repair.ts +70 -0
  171. package/src/reshape.ts +193 -0
  172. package/src/restricted.ts +69 -0
  173. package/src/scheduler.ts +284 -0
  174. package/src/select.ts +59 -0
  175. package/src/shape.ts +39 -0
  176. package/src/split/client.ts +449 -0
  177. package/src/split/index.ts +18 -0
  178. package/src/split/server.ts +746 -0
  179. package/src/split/shared.ts +18 -0
@@ -0,0 +1,416 @@
1
+ import { tainted } from "@loomwork/classify";
2
+ import { TypedFailure } from "@loomwork/core";
3
+ import { shapeOf } from "@loomwork/plugin-sandbox";
4
+ import { checkKindValue, hasKindContract, stepKind, } from "@loomwork/ui-core";
5
+ import { checkContentRefs, contentRefEnv, finishContentRefArgs, } from "./contentRefs";
6
+ import { DEFAULT_DATA_PROVIDERS, } from "./dataProvider";
7
+ import { pickParams, prepareArguments, providerParams, } from "./params";
8
+ import { terminalSteps, topoWaves } from "./plan";
9
+ import { outputShapeHashOf, reshape, safeStringify, } from "./reshape";
10
+ async function mapLimit(items, limit, fn) {
11
+ const results = new Array(items.length);
12
+ let cursor = 0;
13
+ const worker = async () => {
14
+ for (;;) {
15
+ const i = cursor++;
16
+ if (i >= items.length)
17
+ return;
18
+ results[i] = await fn(items[i]);
19
+ }
20
+ };
21
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
22
+ return results;
23
+ }
24
+ const err = (code, message) => ({ code, severity: "error", message });
25
+ /** A step's invocation failed for a reason other than an input-schema drift. */
26
+ function stepFailure(node, e, signal) {
27
+ if (e instanceof TypedFailure)
28
+ return err(`tool-${e.channel}`, `step "${node.stepId}" (${node.toolName}) failed on channel ${e.channel}: ${safeStringify(e.payload)}`);
29
+ if (signal?.aborted)
30
+ return err("aborted", `step "${node.stepId}" aborted`);
31
+ return err("tool-failed", `step "${node.stepId}" (${node.toolName}) failed: ${e instanceof Error ? e.message : String(e)}`);
32
+ }
33
+ /**
34
+ * The shapes an output-drift record carries. Neither value has necessarily been proved walkable
35
+ * (the raw output never went through `shapeHash`): one too deep or too wide simply leaves its
36
+ * field absent — a drift REPORT must never become a throw.
37
+ */
38
+ function observedShapes(value, raw) {
39
+ const out = {};
40
+ try {
41
+ out.observedShape = shapeOf(value);
42
+ }
43
+ catch {
44
+ // unwalkable: leave absent
45
+ }
46
+ try {
47
+ out.observedRawShape = shapeOf(raw);
48
+ }
49
+ catch {
50
+ // unwalkable: leave absent
51
+ }
52
+ return out;
53
+ }
54
+ /** The raw output's shape alone — a failed reshaping has no reshaped value to walk. */
55
+ function observedRawShape(raw) {
56
+ try {
57
+ return { observedRawShape: shapeOf(raw) };
58
+ }
59
+ catch {
60
+ return {};
61
+ }
62
+ }
63
+ /** The PUBLIC code of a step refused by the content-reference guard (literal, unproven ref, or a param the gate refused). */
64
+ export const CONTENT_REF_REFUSED = "content-ref-refused";
65
+ /**
66
+ * The step-level refusals a CLIENT can cause. An explicit set, not a `media-arg-` prefix: the family
67
+ * also holds `media-arg-schema-unknown` (a host/schema defect) and `media-arg-suspect` (a hint), neither
68
+ * of which is a refused argument.
69
+ */
70
+ const CONTENT_REF_REFUSAL_CODES = new Set([
71
+ "media-arg-literal",
72
+ "media-arg-unproven-ref",
73
+ "media-arg-param-refused",
74
+ ]);
75
+ const isContentRefRefusal = (f) => CONTENT_REF_REFUSAL_CODES.has(f.code);
76
+ /**
77
+ * The first finding (graph order) when every step that failed ON ITS OWN failed with the same
78
+ * one of `schema-drift` / `upstream-empty` — the rest were skipped as its dependents
79
+ * (`dependency-failed`) — or when every one of them was refused by the content-reference guard
80
+ * (then `content-ref-refused`, whichever `media-arg-*` case it was). `undefined` for anything else.
81
+ */
82
+ function onlyFailure(steps, failed) {
83
+ let first;
84
+ for (const step of steps) {
85
+ const f = failed.get(step.stepId);
86
+ if (f === undefined || f.code === "dependency-failed")
87
+ continue;
88
+ if (isContentRefRefusal(f)) {
89
+ if (first !== undefined && first.code !== CONTENT_REF_REFUSED)
90
+ return undefined;
91
+ first ??= err(CONTENT_REF_REFUSED, "a content-reference argument was refused: a content address is a capability and only a reference the host vouches for is accepted");
92
+ continue;
93
+ }
94
+ if (f.code !== "schema-drift" && f.code !== "upstream-empty")
95
+ return undefined;
96
+ if (first !== undefined && f.code !== first.code)
97
+ return undefined;
98
+ first ??= f;
99
+ }
100
+ return first;
101
+ }
102
+ /** A published value; carries `drift` only when an input drift was proceeded past. */
103
+ const okOutcome = (value, findings, drift) => drift.length > 0 ? { ok: true, value, findings, drift } : { ok: true, value, findings };
104
+ export async function executeProvider(spec, opts) {
105
+ const findings = [];
106
+ const drift = [];
107
+ const steps = spec.executionGraph;
108
+ if (steps.length === 0)
109
+ return {
110
+ ok: false,
111
+ finding: err("empty-graph", `provider "${spec.handle}" has no steps`),
112
+ drift,
113
+ findings,
114
+ };
115
+ const { waves, cycle } = topoWaves(steps);
116
+ if (cycle.length > 0)
117
+ return {
118
+ ok: false,
119
+ finding: err("graph-cycle", `provider "${spec.handle}" has a dependency cycle through ${cycle.join(", ")}`),
120
+ drift,
121
+ findings,
122
+ };
123
+ const registry = opts.providers ?? DEFAULT_DATA_PROVIDERS;
124
+ // Every kind is resolved BEFORE any step runs: an unregistered one must not leave the steps
125
+ // before it having called their targets for an answer nobody will publish.
126
+ const unregistered = [...new Set(steps.map(stepKind))].filter((k) => !registry.has(k)).sort();
127
+ if (unregistered.length > 0)
128
+ return {
129
+ ok: false,
130
+ finding: err("provider-kind-unregistered", `provider "${spec.handle}" has steps of kind ${unregistered.map((k) => `"${k}"`).join(", ")}, which no data provider is registered for`),
131
+ drift,
132
+ findings,
133
+ };
134
+ const now = opts.now ?? Date.now();
135
+ const supplied = opts.params ?? {};
136
+ const names = providerParams(spec);
137
+ const declared = new Set(names);
138
+ const undeclared = Object.keys(supplied)
139
+ .filter((k) => !declared.has(k))
140
+ .sort();
141
+ // Only the params some step declares reach a step — and the argument hook. A hook that could
142
+ // read an undeclared param could make the answer depend on a value no cache key carries.
143
+ const params = pickParams(supplied, names);
144
+ if (undeclared.length > 0)
145
+ findings.push({
146
+ code: "param-not-overridable",
147
+ severity: "warn",
148
+ message: `provider "${spec.handle}" declares no overridable argument named ${undeclared.map((k) => `"${k}"`).join(", ")}; ignored`,
149
+ });
150
+ const outputs = new Map();
151
+ const failed = new Map();
152
+ const warnings = new Map();
153
+ const warn = (stepId, f) => {
154
+ const list = warnings.get(stepId);
155
+ if (list === undefined)
156
+ warnings.set(stepId, [f]);
157
+ else
158
+ list.push(f);
159
+ };
160
+ const invokeOpts = {
161
+ label: "loom-ui.hydrate",
162
+ ...(opts.signal && { signal: opts.signal }),
163
+ ...(opts.principal && { principal: opts.principal }),
164
+ };
165
+ const refEnv = opts.contentRefArgs === undefined
166
+ ? undefined
167
+ : contentRefEnv(opts.contentRefArgs, spec, opts.acceptContentRefParam, {
168
+ principalId: opts.principalId,
169
+ principal: opts.principal,
170
+ });
171
+ for (const wave of waves) {
172
+ await mapLimit(wave, opts.concurrency ?? 4, async (node) => {
173
+ if (opts.signal?.aborted) {
174
+ failed.set(node.stepId, err("aborted", `step "${node.stepId}" aborted before it ran`));
175
+ return;
176
+ }
177
+ if (node.dependsOn.some((d) => failed.has(d))) {
178
+ failed.set(node.stepId, err("dependency-failed", `step "${node.stepId}" skipped: a dependency failed`));
179
+ return;
180
+ }
181
+ const args = prepareArguments(node, outputs, {
182
+ handle: spec.handle,
183
+ params,
184
+ now,
185
+ ...(opts.argumentHook && { hook: opts.argumentHook }),
186
+ ...(refEnv !== undefined && {
187
+ guard: (n, applied) => checkContentRefs(n, applied, refEnv).finding,
188
+ finish: (a) => finishContentRefArgs(node, a, refEnv.table),
189
+ }),
190
+ });
191
+ if (!args.ok) {
192
+ failed.set(node.stepId, args.finding);
193
+ return;
194
+ }
195
+ for (const f of args.findings)
196
+ warn(node.stepId, f);
197
+ const dataProvider = registry.get(stepKind(node));
198
+ const call = (expectedPin) => dataProvider.invoke({ stepId: node.stepId, target: node.toolName, args: args.args, expectedPin }, opts.invoker, invokeOpts);
199
+ try {
200
+ outputs.set(node.stepId, await call(node.toolSchemaHash));
201
+ }
202
+ catch (e) {
203
+ if (!(e instanceof TypedFailure && e.channel === "schemaDrift")) {
204
+ failed.set(node.stepId, stepFailure(node, e, opts.signal));
205
+ return;
206
+ }
207
+ const observed = e.payload?.observedHash;
208
+ drift.push({
209
+ kind: "input",
210
+ handle: spec.handle,
211
+ stepId: node.stepId,
212
+ toolName: node.toolName,
213
+ ...(node.kind !== undefined && { providerKind: node.kind }),
214
+ expected: node.toolSchemaHash,
215
+ observed: observed ?? "",
216
+ });
217
+ const proceed = opts.inputDrift === "report-and-proceed" &&
218
+ observed !== undefined &&
219
+ observed !== "" &&
220
+ observed !== node.toolSchemaHash;
221
+ if (!proceed) {
222
+ failed.set(node.stepId, err("schema-drift", `step "${node.stepId}" (${node.toolName}) input schema drifted from ${node.toolSchemaHash} to ${observed ?? "?"}`));
223
+ return;
224
+ }
225
+ try {
226
+ outputs.set(node.stepId, await call(observed));
227
+ warn(node.stepId, {
228
+ code: "schema-drift-proceeded",
229
+ severity: "warn",
230
+ message: `step "${node.stepId}" (${node.toolName}) input schema drifted from ${node.toolSchemaHash} to ${observed}; loaded once with the observed pin — the provider still needs its repair`,
231
+ });
232
+ }
233
+ catch (retry) {
234
+ failed.set(node.stepId, stepFailure(node, retry, opts.signal));
235
+ }
236
+ }
237
+ });
238
+ }
239
+ // GRAPH order, not completion order: two independent steps that fail (or warn) in a race must
240
+ // produce the same finding list every run, or the surface's text depends on which tool was slower.
241
+ for (const step of steps)
242
+ for (const f of warnings.get(step.stepId) ?? [])
243
+ findings.push(f);
244
+ for (const step of steps) {
245
+ const f = failed.get(step.stepId);
246
+ if (f)
247
+ findings.push(f);
248
+ }
249
+ if (failed.size > 0) {
250
+ // A provider that failed ONLY because of input drift (every step that failed on its own
251
+ // drifted; the rest were skipped as its dependents) answers with the first drift in graph
252
+ // order, so the surface says "waiting for a repair" rather than a generic failure. The same
253
+ // rule for an EMPTY upstream (every step that failed on its own found no such row upstream,
254
+ // `upstream-empty`): the answer is the first one, published `empty` (loom ADR 0100). Any
255
+ // other failure alongside either — or the two mixed — keeps the generic `provider-failed`.
256
+ const only = onlyFailure(steps, failed);
257
+ if (only !== undefined)
258
+ return { ok: false, finding: only, drift, findings };
259
+ return {
260
+ ok: false,
261
+ finding: err("provider-failed", `provider "${spec.handle}": ${failed.size} of ${steps.length} steps failed`),
262
+ drift,
263
+ findings,
264
+ };
265
+ }
266
+ const terminals = terminalSteps(steps);
267
+ const raw = terminals.length === 1
268
+ ? outputs.get(terminals[0].stepId)
269
+ : Object.fromEntries(terminals.map((t) => [t.stepId, outputs.get(t.stepId)]));
270
+ const shaped = await reshape(spec.reshaping, raw, {
271
+ invoker: opts.invoker,
272
+ ...(opts.signal && { signal: opts.signal }),
273
+ ...(opts.principal && { principal: opts.principal }),
274
+ ...(opts.reshapers && { reshapers: opts.reshapers }),
275
+ });
276
+ if (!shaped.ok) {
277
+ findings.push(shaped.finding);
278
+ // Only a failure the OUTPUT demonstrably caused (typed by `reshape`, never read from a
279
+ // message) is output drift a planner can repair — so, like a failed pin, the record carries
280
+ // the raw output's shape and (under `captureSample`) its sample. Infrastructure and transient
281
+ // failures carry no `failureKind`, and stay an error with no drift.
282
+ if (shaped.failureKind !== undefined && opts.signal?.aborted !== true)
283
+ drift.push({
284
+ kind: "output",
285
+ handle: spec.handle,
286
+ expected: "reshape",
287
+ observed: shaped.finding.code,
288
+ reshapeFailure: shaped.finding.code,
289
+ reshapeFailureKind: shaped.failureKind,
290
+ ...(terminals.length === 1 && { stepId: terminals[0].stepId }),
291
+ ...observedRawShape(raw),
292
+ // An uncloneable output is not a data observation: no sample, even under captureSample.
293
+ ...(opts.captureSample === true &&
294
+ shaped.failureKind !== "uncloneable-output" && {
295
+ observedSample: tainted(raw, `provider:${spec.handle}`),
296
+ }),
297
+ });
298
+ return { ok: false, finding: shaped.finding, drift, findings };
299
+ }
300
+ if (spec.outputCheck === "contract")
301
+ return checkContract(spec, shaped.value, raw, opts, drift, findings, terminals);
302
+ if (spec.outputShapeHash === "") {
303
+ findings.push({
304
+ code: "output-shape-unpinned",
305
+ severity: "warn",
306
+ message: `provider "${spec.handle}" declares no outputShapeHash; the value is unchecked`,
307
+ });
308
+ return okOutcome(shaped.value, findings, drift);
309
+ }
310
+ // The shaped value is tool-authored: `shapeHash` refuses a nest past its depth cap (and any
311
+ // value it cannot walk). An unhashable value is an UNVERIFIABLE one — reported as a failure,
312
+ // never published as if the pin had matched, and never as a throw out of this total function.
313
+ let observed;
314
+ try {
315
+ observed = outputShapeHashOf(shaped.value);
316
+ }
317
+ catch (e) {
318
+ const f = err("output-shape-unhashable", `provider "${spec.handle}" output cannot be shape-hashed, so the pinned ${spec.outputShapeHash} cannot be checked: ${e instanceof Error ? e.message : String(e)}`);
319
+ findings.push(f);
320
+ return { ok: false, finding: f, drift, findings };
321
+ }
322
+ if (observed !== spec.outputShapeHash) {
323
+ drift.push({
324
+ kind: "output",
325
+ handle: spec.handle,
326
+ expected: spec.outputShapeHash,
327
+ observed,
328
+ ...(terminals.length === 1 && { stepId: terminals[0].stepId }),
329
+ ...observedShapes(shaped.value, raw),
330
+ ...(opts.captureSample === true && {
331
+ observedSample: tainted(raw, `provider:${spec.handle}`),
332
+ }),
333
+ });
334
+ const f = err("output-shape-drift", `provider "${spec.handle}" output shape ${observed} differs from the pinned ${spec.outputShapeHash}`);
335
+ findings.push(f);
336
+ return { ok: false, finding: f, drift, findings };
337
+ }
338
+ return okOutcome(shaped.value, findings, drift);
339
+ }
340
+ /**
341
+ * `outputCheck: "contract"`: the reshaped value must satisfy the value contract of EVERY kind the
342
+ * handle feeds (each widget renders the same value); kinds are checked in sorted order and the
343
+ * first failure is the drift. `undefined` is refused explicitly — `checkKindValue` passes it as
344
+ * "not hydrated yet", but a load that produced nothing is not a healthy value.
345
+ */
346
+ function checkContract(spec, value, raw, opts, drift, findings, terminals) {
347
+ const kinds = [...new Set(opts.kinds ?? [])].sort();
348
+ if (kinds.length === 0) {
349
+ const f = err("output-contract-unbound", `provider "${spec.handle}" checks its output by contract, but no bound kinds were supplied; the value cannot be checked`);
350
+ findings.push(f);
351
+ return { ok: false, finding: f, drift, findings };
352
+ }
353
+ // A contract check over a kind with NO contract passes every value, and a green check nobody
354
+ // populated reads as coverage. So it is a refusal — and no drift record: reshaping the value
355
+ // differently cannot repair a missing contract, which is the catalogue's to declare.
356
+ const uncontracted = kinds.filter((k) => !hasKindContract(k, opts.contracts));
357
+ if (uncontracted.length > 0) {
358
+ const f = err("output-contract-missing", `provider "${spec.handle}" checks its output by contract, but kind${uncontracted.length > 1 ? "s" : ""} ${uncontracted.map((k) => `"${k}"`).join(", ")} ${uncontracted.length > 1 ? "have" : "has"} no value contract (declare one in the catalogue's valueContracts); the value cannot be checked`);
359
+ findings.push(f);
360
+ return { ok: false, finding: f, drift, findings };
361
+ }
362
+ for (const kind of kinds) {
363
+ const r = value === undefined
364
+ ? {
365
+ ok: false,
366
+ finding: err("value-contract", `value for kind "${kind}" is undefined: the reshaping produced nothing`),
367
+ }
368
+ : checkKindValue(kind, value, opts.contracts);
369
+ if (r.ok)
370
+ continue;
371
+ let observed = "unhashable";
372
+ try {
373
+ observed = outputShapeHashOf(value);
374
+ }
375
+ catch {
376
+ // Too deep to hash: the contract failure below is still reported.
377
+ }
378
+ drift.push({
379
+ kind: "output",
380
+ handle: spec.handle,
381
+ expected: `contract:${kind}`,
382
+ observed,
383
+ contractKind: kind,
384
+ ...(terminals.length === 1 && { stepId: terminals[0].stepId }),
385
+ ...observedShapes(value, raw),
386
+ ...(opts.captureSample === true && {
387
+ observedSample: tainted(raw, `provider:${spec.handle}`),
388
+ }),
389
+ });
390
+ const f = err("output-contract-drift", `provider "${spec.handle}": ${r.finding.message}`);
391
+ findings.push(f);
392
+ return { ok: false, finding: f, drift, findings };
393
+ }
394
+ return okOutcome(value, findings, drift);
395
+ }
396
+ /**
397
+ * What an outcome publishes — the ONE mapping both the in-process controller and `serveHandle`
398
+ * use, so split and in-process hydration cannot disagree: a value is `ready` (carrying the first
399
+ * warning, e.g. a proceeded drift); an `upstream-empty` failure is `empty` — checked FIRST, and
400
+ * carrying no value (loom ADR 0100: a producer MUST clear the value beside `empty`); a failure
401
+ * with drift is `stale` — unless its only drift is a failed reshaping (`reshapeFailure`), which
402
+ * stays `error` as it always was — and any other failure `error`.
403
+ */
404
+ export function outcomeResult(outcome) {
405
+ if (outcome.ok) {
406
+ const warn = outcome.findings.find((f) => f.severity === "warn");
407
+ return warn === undefined
408
+ ? { state: "ready", value: outcome.value }
409
+ : { state: "ready", value: outcome.value, finding: warn };
410
+ }
411
+ if (outcome.finding.code === "upstream-empty")
412
+ return { state: "empty", finding: outcome.finding };
413
+ const stale = outcome.drift.some((d) => d.reshapeFailure === undefined);
414
+ return { state: stale ? "stale" : "error", finding: outcome.finding };
415
+ }
416
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ // ── Crossing the determinism boundary ─────────────────────────────────────────
2
+ // Hydration REPORTS drift; it never repairs. The app runs a durable loom execution that applies
3
+ // the operation built here (via core's `apply`, so the artifact's lineage records it), emits
4
+ // SCHEMA_REPAIRED with this payload, and re-seals. Input drift (a tool's input schema moved) is a
5
+ // pin move and can be remapped mechanically; output drift (the reshaped value's shape changed)
6
+ // means the reshaping is wrong for the data and needs the planner — that is a different slice.
7
+ export const SCHEMA_REPAIRED = "SCHEMA_REPAIRED";
8
+ export function remapOperation(spec, drift) {
9
+ if (drift.length === 0)
10
+ return {
11
+ ok: false,
12
+ finding: { code: "repair-mismatch", severity: "error", message: "no drift to repair" },
13
+ };
14
+ if (drift.some((d) => d.kind === "output"))
15
+ return {
16
+ ok: false,
17
+ finding: {
18
+ code: "repair-needs-planner",
19
+ severity: "error",
20
+ message: `provider "${spec.handle}": output shape drifted; remapping a pin cannot fix a reshaping that no longer matches the data`,
21
+ },
22
+ };
23
+ const steps = new Map(spec.executionGraph.map((s) => [s.stepId, s]));
24
+ for (const d of drift) {
25
+ if (d.handle !== spec.handle)
26
+ return {
27
+ ok: false,
28
+ finding: {
29
+ code: "repair-mismatch",
30
+ severity: "error",
31
+ message: `drift for "${d.handle}" applied to provider "${spec.handle}"`,
32
+ },
33
+ };
34
+ if (d.stepId === undefined || !steps.has(d.stepId))
35
+ return {
36
+ ok: false,
37
+ finding: {
38
+ code: "repair-mismatch",
39
+ severity: "error",
40
+ message: `drift names step "${d.stepId ?? "?"}", which provider "${spec.handle}" does not have`,
41
+ },
42
+ };
43
+ }
44
+ const observedByStep = new Map(drift.map((d) => [d.stepId, d.observed]));
45
+ const executionGraph = spec.executionGraph.map((s) => observedByStep.has(s.stepId)
46
+ ? { ...s, toolSchemaHash: observedByStep.get(s.stepId) }
47
+ : s);
48
+ return {
49
+ ok: true,
50
+ op: { type: "remapProvider", handle: spec.handle, spec: { ...spec, executionGraph } },
51
+ };
52
+ }
53
+ //# sourceMappingURL=repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repair.js","sourceRoot":"","sources":["../../src/repair.ts"],"names":[],"mappings":"AAGA,iFAAiF;AACjF,gGAAgG;AAChG,6FAA6F;AAC7F,kGAAkG;AAClG,+FAA+F;AAC/F,+FAA+F;AAE/F,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAUjD,MAAM,UAAU,cAAc,CAC5B,IAAkB,EAClB,KAA6B;IAE7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QACpB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE;SACvF,CAAC;IACJ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE;gBACP,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,aAAa,IAAI,CAAC,MAAM,iGAAiG;aACnI;SACF,CAAC;IACJ,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAU,CAAC,CAAC,CAAC;IAC9E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAC1B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE;oBACP,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,cAAc,CAAC,CAAC,MAAM,0BAA0B,IAAI,CAAC,MAAM,GAAG;iBACxE;aACF,CAAC;QACJ,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAChD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EAAE;oBACP,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,qBAAqB,CAAC,CAAC,MAAM,IAAI,GAAG,sBAAsB,IAAI,CAAC,MAAM,iBAAiB;iBAChG;aACF,CAAC;IACN,CAAC;IACD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnD,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1B,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAW,EAAE;QAClE,CAAC,CAAC,CAAC,CACN,CAAC;IACF,OAAO;QACL,EAAE,EAAE,IAAI;QACR,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,cAAc,EAAE,EAAE;KACtF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,156 @@
1
+ import { TypedFailure } from "@loomwork/core";
2
+ import { SANDBOX_TOOL_ID } from "@loomwork/plugin-sandbox";
3
+ import { jsonPathSelect } from "./select";
4
+ /**
5
+ * The channel loom's sandbox completes on when the SCRIPT itself threw on its input (its own
6
+ * exception, a SyntaxError, a ReferenceError for a global the VM lacks). Recognised by channel
7
+ * only: its payload (`{ name?, message }`) is script-authored, UNTRUSTED text — it can echo the
8
+ * raw output — so it is never read, and never copied into a finding message.
9
+ */
10
+ const SCRIPT_ERROR = "scriptError";
11
+ const LIMIT_EXCEEDED = "limitExceeded";
12
+ /** A sandbox `TypedFailure` → the output-caused kind it proves, if any. Channel + payload only. */
13
+ function sandboxFailureKind(e) {
14
+ if (e.channel === SCRIPT_ERROR)
15
+ return "script-error";
16
+ if (e.channel !== LIMIT_EXCEEDED)
17
+ return undefined;
18
+ const kind = e.payload?.kind;
19
+ if (kind === "cpu")
20
+ return "limit-cpu";
21
+ if (kind === "memory")
22
+ return "limit-memory";
23
+ if (kind === "output")
24
+ return "limit-output";
25
+ return undefined; // wallClock (host-load dependent) or an unknown kind
26
+ }
27
+ /**
28
+ * A registry over a plain record. Map-backed, so only the record's OWN entries are registered —
29
+ * `"constructor"` or `"__proto__"` never resolve to something on a prototype.
30
+ */
31
+ export function defineReshapers(entries) {
32
+ const byName = new Map(Object.entries(entries));
33
+ return { get: (name) => byName.get(name) };
34
+ }
35
+ /**
36
+ * A Named reshaper runs in-process, trusted like host code — but the RAW terminal output is also
37
+ * read by callers after `reshape` returns (output-shape hashing, drift sampling): a reshaper that
38
+ * mutates its input in place must never corrupt what those later readers see, so it gets a copy,
39
+ * never the original reference. A raw value `structuredClone` cannot represent anywhere in its
40
+ * tree (a function; `structuredClone` throws) is REFUSED rather than handed to the reshaper live
41
+ * — that would let the reshaper corrupt what later readers see, exactly what the copy exists to
42
+ * prevent. (A class instance is not this case: `structuredClone` clones it fine, it just drops
43
+ * the prototype, so the copy is a plain object with the same own properties.) Throws; `runNamed`
44
+ * turns that into a `reshape-failed` finding before the reshaper ever runs.
45
+ */
46
+ function cloneForReshaper(raw) {
47
+ try {
48
+ return structuredClone(raw);
49
+ }
50
+ catch {
51
+ throw new Error("input is not cloneable");
52
+ }
53
+ }
54
+ async function runNamed(name, raw, registry) {
55
+ const fn = registry?.get(name);
56
+ if (fn === undefined)
57
+ return {
58
+ ok: false,
59
+ finding: {
60
+ code: "reshape-unregistered",
61
+ severity: "error",
62
+ message: registry === undefined
63
+ ? `reshaper "${name}" is Named, but no reshaper registry was supplied`
64
+ : `no reshaper is registered under "${name}"`,
65
+ },
66
+ };
67
+ let cloned;
68
+ try {
69
+ cloned = cloneForReshaper(raw);
70
+ }
71
+ catch (err) {
72
+ // The OUTPUT is the cause: it holds a value that cannot be copied, so the reshaper never runs.
73
+ return {
74
+ ok: false,
75
+ failureKind: "uncloneable-output",
76
+ finding: {
77
+ code: "reshape-failed",
78
+ severity: "error",
79
+ message: `reshaper "${name}": ${err instanceof Error ? err.message : String(err)}`,
80
+ },
81
+ };
82
+ }
83
+ try {
84
+ return { ok: true, value: await fn(cloned) };
85
+ }
86
+ catch (err) {
87
+ // Host code threw: not proven output-caused, so no kind — a plain error, not drift.
88
+ return {
89
+ ok: false,
90
+ finding: {
91
+ code: "reshape-failed",
92
+ severity: "error",
93
+ message: `reshaper "${name}" failed: ${err instanceof Error ? err.message : String(err)}`,
94
+ },
95
+ };
96
+ }
97
+ }
98
+ /**
99
+ * A finding MESSAGE must never be the thing that throws. A `TypedFailure` payload is authored by
100
+ * a tool server or a sandbox script — it can be cyclic, or carry a bigint, and `JSON.stringify`
101
+ * throws on both. Losing the payload text is a far better outcome than losing the finding.
102
+ * (Not exported from the package index: it exists for this package's message building.)
103
+ */
104
+ export function safeStringify(v) {
105
+ try {
106
+ return JSON.stringify(v) ?? String(v);
107
+ }
108
+ catch {
109
+ return "[unserializable payload]";
110
+ }
111
+ }
112
+ export async function reshape(reshaping, raw, ctx) {
113
+ if (reshaping.engine === "JSONPath")
114
+ return jsonPathSelect(raw, reshaping.scriptRef);
115
+ if (reshaping.engine === "Named")
116
+ return runNamed(reshaping.scriptRef, raw, ctx.reshapers);
117
+ try {
118
+ const value = await ctx.invoker.invokeTransient(SANDBOX_TOOL_ID, { scriptRef: { __loomContent: reshaping.scriptRef }, input: raw }, {
119
+ label: "loom-ui.reshape",
120
+ ...(ctx.signal && { signal: ctx.signal }),
121
+ ...(ctx.principal && { principal: ctx.principal }),
122
+ });
123
+ return { ok: true, value };
124
+ }
125
+ catch (err) {
126
+ if (err instanceof TypedFailure) {
127
+ const failureKind = sandboxFailureKind(err);
128
+ return {
129
+ ok: false,
130
+ ...(failureKind !== undefined && { failureKind }),
131
+ finding: {
132
+ code: `reshape-${err.channel}`,
133
+ severity: "error",
134
+ // A `scriptError` payload is script-authored text that can echo the raw output
135
+ // (possibly sensitive, untrusted): fixed text only, never its `name` or `message` —
136
+ // no finding, handle status or log hook ever carries it. The raw output travels only
137
+ // as the tainted drift sample. Other channels' payloads are loom-authored.
138
+ message: failureKind === "script-error"
139
+ ? `reshape script ${reshaping.scriptRef} failed on the output (script-error)`
140
+ : `sandbox ${err.channel}: ${safeStringify(err.payload)}`,
141
+ },
142
+ };
143
+ }
144
+ return {
145
+ ok: false,
146
+ finding: {
147
+ code: "reshape-failed",
148
+ severity: "error",
149
+ message: err instanceof Error ? err.message : String(err),
150
+ },
151
+ };
152
+ }
153
+ }
154
+ export { outputShapeHashOf } from "./shape";
155
+ export { jsonPathSelect } from "./select";
156
+ //# sourceMappingURL=reshape.js.map