@fungi.computer/darkroom 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -156,9 +156,18 @@ Agar's public `pendingSchema`. `appMediaModelsOutcomeSchema` and
156
156
  closed admission codes, the Media attachment-budget refusal, the existing
157
157
  `agentAppMediaLibraryFailureSchema`, and `appMediaBrokerFailureSchema`. The
158
158
  latter preserves the broker projection: HTTP `code` becomes `error`, HTTP
159
- `error` becomes `message`, and `stage` and `retryable` stay unchanged. HTTP
160
- failures and transport envelopes are separate representations and do not decode
161
- as these outcomes.
159
+ `error` becomes `message`, and `stage`, `retryable` and optional `provider`
160
+ facts stay unchanged. HTTP failures and transport envelopes are separate
161
+ representations and do not decode as these outcomes.
162
+
163
+ Provider facts use Agar's canonical Media grammar: an allowlisted error category
164
+ and bounded numeric code, or `result_download` and a native HTTP status. The
165
+ durable owner retains those facts through interruption and replay, including
166
+ safety refusals, without retaining the original error message or cause in the
167
+ failure record. A terminal provider failure never redispatches the paid attempt.
168
+ The fresh pre-release schema replaces the safety-only refusal table; old preview
169
+ stores require an explicit host reset, not an automatic migration or dual
170
+ reader.
162
171
 
163
172
  See the [generated API](docs/api/README.md) for signatures and host ports. The
164
173
  Cloudflare entry needs the native Workers type declarations in a TypeScript
@@ -1,6 +1,6 @@
1
1
  import * as z from "zod";
2
2
  /** Bounded catalog decoded by the App media broker before host filtering. */
3
- export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
3
+ export declare const mediaModelsSchema: z.ZodLazy<z.ZodArray<z.ZodReadonly<z.ZodObject<{
4
4
  id: z.ZodString;
5
5
  label: z.ZodString;
6
6
  kind: z.ZodEnum<{
@@ -18,7 +18,7 @@ export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
18
18
  readonly jpeg: "jpeg";
19
19
  readonly webp: "webp";
20
20
  }>>>;
21
- input: z.ZodReadonly<z.ZodObject<{
21
+ input: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
22
22
  transport: z.ZodEnum<{
23
23
  readonly json: "json";
24
24
  readonly multipart: "multipart";
@@ -39,9 +39,9 @@ export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
39
39
  defaultSteps: z.ZodNullable<z.ZodNumber>;
40
40
  referenceField: z.ZodNullable<z.ZodString>;
41
41
  maxReferences: z.ZodNumber;
42
- }, z.core.$strict>>;
42
+ }, z.core.$strict>>>;
43
43
  sizes: z.ZodNullable<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
44
- video: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
44
+ video: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
45
45
  minSeconds: z.ZodNumber;
46
46
  maxSeconds: z.ZodNumber;
47
47
  defaultSeconds: z.ZodNumber;
@@ -51,7 +51,7 @@ export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
51
51
  readonly veo: "veo";
52
52
  readonly minimax: "minimax";
53
53
  }>;
54
- formats: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
54
+ formats: z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
55
55
  resolution: z.ZodEnum<{
56
56
  readonly p480: "480p";
57
57
  readonly p720: "720p";
@@ -70,7 +70,7 @@ export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
70
70
  }>;
71
71
  width: z.ZodNumber;
72
72
  height: z.ZodNumber;
73
- }, z.core.$strict>>>>;
73
+ }, z.core.$strict>>>>>;
74
74
  defaultResolution: z.ZodEnum<{
75
75
  readonly p480: "480p";
76
76
  readonly p720: "720p";
@@ -113,8 +113,8 @@ export declare const mediaModelsSchema: z.ZodArray<z.ZodReadonly<z.ZodObject<{
113
113
  silentMilliunitsPerSecond: z.ZodNumber;
114
114
  audioMilliunitsPerSecond: z.ZodNumber;
115
115
  }, z.core.$strict>>>>;
116
- }, z.core.$strict>>>;
117
- }, z.core.$strict>>>;
116
+ }, z.core.$strict>>>>;
117
+ }, z.core.$strict>>>>;
118
118
  /** An absolute output path on the Computer admitted by the App host. */
119
119
  export declare const destinationSchema: z.ZodObject<{
120
120
  computerId: z.ZodString;
@@ -153,11 +153,11 @@ export declare const appMediaAdmissionErrorSchema: z.ZodObject<{
153
153
  }>;
154
154
  }, z.core.$strict>;
155
155
  /** Attachment budget refusal emitted by the Media reservation owner. */
156
- export declare const appMediaBudgetRefusalSchema: z.ZodObject<{
156
+ export declare const appMediaBudgetRefusalSchema: z.ZodLazy<z.ZodObject<{
157
157
  error: z.ZodLiteral<"attachment_budget_exceeded">;
158
158
  kind: z.ZodLiteral<"media">;
159
159
  retryAfterMs: z.ZodNumber;
160
- }, z.core.$strict>;
160
+ }, z.core.$strict>>;
161
161
  /** Existing Media admission refusals, without an admitted selector or callable. */
162
162
  export declare const appMediaAdmissionRefusalSchema: z.ZodUnion<readonly [z.ZodObject<{
163
163
  error: z.ZodEnum<{
@@ -170,11 +170,11 @@ export declare const appMediaAdmissionRefusalSchema: z.ZodUnion<readonly [z.ZodO
170
170
  /** Admission could not resolve the current resource. */
171
171
  readonly unavailable: "unavailable";
172
172
  }>;
173
- }, z.core.$strict>, z.ZodObject<{
173
+ }, z.core.$strict>, z.ZodLazy<z.ZodObject<{
174
174
  error: z.ZodLiteral<"attachment_budget_exceeded">;
175
175
  kind: z.ZodLiteral<"media">;
176
176
  retryAfterMs: z.ZodNumber;
177
- }, z.core.$strict>]>;
177
+ }, z.core.$strict>>]>;
178
178
  /** Admission errors plus invalid/oversized inputs emitted directly by the broker. */
179
179
  export declare const appMediaBrokerErrorSchema: z.ZodObject<{
180
180
  error: z.ZodEnum<{
@@ -193,10 +193,10 @@ export declare const appMediaBrokerErrorSchema: z.ZodObject<{
193
193
  }>;
194
194
  }, z.core.$strict>;
195
195
  /** Missing-library refusal decoded and returned by the App media broker. */
196
- export declare const agentAppMediaLibraryFailureSchema: z.ZodObject<{
196
+ export declare const agentAppMediaLibraryFailureSchema: z.ZodLazy<z.ZodObject<{
197
197
  error: z.ZodLiteral<"library_unavailable">;
198
198
  message: z.ZodString;
199
- }, z.core.$strict>;
199
+ }, z.core.$strict>>;
200
200
  /** Broker projection of an HTTP failure: code becomes error and error becomes message. */
201
201
  export declare const appMediaBrokerFailureSchema: z.ZodObject<{
202
202
  error: z.ZodEnum<{
@@ -221,6 +221,13 @@ export declare const appMediaBrokerFailureSchema: z.ZodObject<{
221
221
  readonly "destination-write": "destination-write";
222
222
  }>;
223
223
  retryable: z.ZodBoolean;
224
+ provider: z.ZodOptional<z.ZodPipe<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodTransform<Readonly<{
225
+ category: "InferenceUpstreamError" | "AiInternalError" | "TypeError" | "AbortError" | "TimeoutError" | "Error";
226
+ code: number | null;
227
+ }> | Readonly<{
228
+ category: "result_download";
229
+ status: number;
230
+ }>, unknown>>>;
224
231
  }, z.core.$strict>;
225
232
  /** Refusal payloads emitted by the App media broker, separate from transport errors. */
226
233
  export declare const appMediaRefusalSchema: z.ZodUnion<readonly [z.ZodObject<{
@@ -238,14 +245,14 @@ export declare const appMediaRefusalSchema: z.ZodUnion<readonly [z.ZodObject<{
238
245
  /** Admission could not resolve the current resource. */
239
246
  readonly unavailable: "unavailable";
240
247
  }>;
241
- }, z.core.$strict>, z.ZodObject<{
248
+ }, z.core.$strict>, z.ZodLazy<z.ZodObject<{
242
249
  error: z.ZodLiteral<"attachment_budget_exceeded">;
243
250
  kind: z.ZodLiteral<"media">;
244
251
  retryAfterMs: z.ZodNumber;
245
- }, z.core.$strict>, z.ZodObject<{
252
+ }, z.core.$strict>>, z.ZodLazy<z.ZodObject<{
246
253
  error: z.ZodLiteral<"library_unavailable">;
247
254
  message: z.ZodString;
248
- }, z.core.$strict>, z.ZodObject<{
255
+ }, z.core.$strict>>, z.ZodObject<{
249
256
  error: z.ZodEnum<{
250
257
  readonly CAPABILITY_DENIED: "CAPABILITY_DENIED";
251
258
  readonly INSUFFICIENT_CREDIT: "INSUFFICIENT_CREDIT";
@@ -268,9 +275,16 @@ export declare const appMediaRefusalSchema: z.ZodUnion<readonly [z.ZodObject<{
268
275
  readonly "destination-write": "destination-write";
269
276
  }>;
270
277
  retryable: z.ZodBoolean;
278
+ provider: z.ZodOptional<z.ZodPipe<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodTransform<Readonly<{
279
+ category: "InferenceUpstreamError" | "AiInternalError" | "TypeError" | "AbortError" | "TimeoutError" | "Error";
280
+ code: number | null;
281
+ }> | Readonly<{
282
+ category: "result_download";
283
+ status: number;
284
+ }>, unknown>>>;
271
285
  }, z.core.$strict>]>;
272
286
  /** Model-list payload or an existing broker refusal. */
273
- export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArray<z.ZodReadonly<z.ZodObject<{
287
+ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodLazy<z.ZodArray<z.ZodReadonly<z.ZodObject<{
274
288
  id: z.ZodString;
275
289
  label: z.ZodString;
276
290
  kind: z.ZodEnum<{
@@ -288,7 +302,7 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
288
302
  readonly jpeg: "jpeg";
289
303
  readonly webp: "webp";
290
304
  }>>>;
291
- input: z.ZodReadonly<z.ZodObject<{
305
+ input: z.ZodLazy<z.ZodReadonly<z.ZodObject<{
292
306
  transport: z.ZodEnum<{
293
307
  readonly json: "json";
294
308
  readonly multipart: "multipart";
@@ -309,9 +323,9 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
309
323
  defaultSteps: z.ZodNullable<z.ZodNumber>;
310
324
  referenceField: z.ZodNullable<z.ZodString>;
311
325
  maxReferences: z.ZodNumber;
312
- }, z.core.$strict>>;
326
+ }, z.core.$strict>>>;
313
327
  sizes: z.ZodNullable<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
314
- video: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
328
+ video: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
315
329
  minSeconds: z.ZodNumber;
316
330
  maxSeconds: z.ZodNumber;
317
331
  defaultSeconds: z.ZodNumber;
@@ -321,7 +335,7 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
321
335
  readonly veo: "veo";
322
336
  readonly minimax: "minimax";
323
337
  }>;
324
- formats: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
338
+ formats: z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
325
339
  resolution: z.ZodEnum<{
326
340
  readonly p480: "480p";
327
341
  readonly p720: "720p";
@@ -340,7 +354,7 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
340
354
  }>;
341
355
  width: z.ZodNumber;
342
356
  height: z.ZodNumber;
343
- }, z.core.$strict>>>>;
357
+ }, z.core.$strict>>>>>;
344
358
  defaultResolution: z.ZodEnum<{
345
359
  readonly p480: "480p";
346
360
  readonly p720: "720p";
@@ -383,8 +397,8 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
383
397
  silentMilliunitsPerSecond: z.ZodNumber;
384
398
  audioMilliunitsPerSecond: z.ZodNumber;
385
399
  }, z.core.$strict>>>>;
386
- }, z.core.$strict>>>;
387
- }, z.core.$strict>>>, z.ZodUnion<readonly [z.ZodObject<{
400
+ }, z.core.$strict>>>>;
401
+ }, z.core.$strict>>>>, z.ZodUnion<readonly [z.ZodObject<{
388
402
  error: z.ZodEnum<{
389
403
  /** The broker refused the input representation or selection. */
390
404
  readonly invalid: "invalid";
@@ -399,14 +413,14 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
399
413
  /** Admission could not resolve the current resource. */
400
414
  readonly unavailable: "unavailable";
401
415
  }>;
402
- }, z.core.$strict>, z.ZodObject<{
416
+ }, z.core.$strict>, z.ZodLazy<z.ZodObject<{
403
417
  error: z.ZodLiteral<"attachment_budget_exceeded">;
404
418
  kind: z.ZodLiteral<"media">;
405
419
  retryAfterMs: z.ZodNumber;
406
- }, z.core.$strict>, z.ZodObject<{
420
+ }, z.core.$strict>>, z.ZodLazy<z.ZodObject<{
407
421
  error: z.ZodLiteral<"library_unavailable">;
408
422
  message: z.ZodString;
409
- }, z.core.$strict>, z.ZodObject<{
423
+ }, z.core.$strict>>, z.ZodObject<{
410
424
  error: z.ZodEnum<{
411
425
  readonly CAPABILITY_DENIED: "CAPABILITY_DENIED";
412
426
  readonly INSUFFICIENT_CREDIT: "INSUFFICIENT_CREDIT";
@@ -429,6 +443,13 @@ export declare const appMediaModelsOutcomeSchema: z.ZodUnion<readonly [z.ZodArra
429
443
  readonly "destination-write": "destination-write";
430
444
  }>;
431
445
  retryable: z.ZodBoolean;
446
+ provider: z.ZodOptional<z.ZodPipe<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodTransform<Readonly<{
447
+ category: "InferenceUpstreamError" | "AiInternalError" | "TypeError" | "AbortError" | "TimeoutError" | "Error";
448
+ code: number | null;
449
+ }> | Readonly<{
450
+ category: "result_download";
451
+ status: number;
452
+ }>, unknown>>>;
432
453
  }, z.core.$strict>]>]>;
433
454
  /** Completed generation, Agar polling result, or an existing broker refusal. */
434
455
  export declare const appMediaGenerationOutcomeSchema: z.ZodUnion<readonly [z.ZodObject<{
@@ -466,14 +487,14 @@ export declare const appMediaGenerationOutcomeSchema: z.ZodUnion<readonly [z.Zod
466
487
  /** Admission could not resolve the current resource. */
467
488
  readonly unavailable: "unavailable";
468
489
  }>;
469
- }, z.core.$strict>, z.ZodObject<{
490
+ }, z.core.$strict>, z.ZodLazy<z.ZodObject<{
470
491
  error: z.ZodLiteral<"attachment_budget_exceeded">;
471
492
  kind: z.ZodLiteral<"media">;
472
493
  retryAfterMs: z.ZodNumber;
473
- }, z.core.$strict>, z.ZodObject<{
494
+ }, z.core.$strict>>, z.ZodLazy<z.ZodObject<{
474
495
  error: z.ZodLiteral<"library_unavailable">;
475
496
  message: z.ZodString;
476
- }, z.core.$strict>, z.ZodObject<{
497
+ }, z.core.$strict>>, z.ZodObject<{
477
498
  error: z.ZodEnum<{
478
499
  readonly CAPABILITY_DENIED: "CAPABILITY_DENIED";
479
500
  readonly INSUFFICIENT_CREDIT: "INSUFFICIENT_CREDIT";
@@ -496,4 +517,11 @@ export declare const appMediaGenerationOutcomeSchema: z.ZodUnion<readonly [z.Zod
496
517
  readonly "destination-write": "destination-write";
497
518
  }>;
498
519
  retryable: z.ZodBoolean;
520
+ provider: z.ZodOptional<z.ZodPipe<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodTransform<Readonly<{
521
+ category: "InferenceUpstreamError" | "AiInternalError" | "TypeError" | "AbortError" | "TimeoutError" | "Error";
522
+ code: number | null;
523
+ }> | Readonly<{
524
+ category: "result_download";
525
+ status: number;
526
+ }>, unknown>>>;
499
527
  }, z.core.$strict>]>]>;
@@ -4,9 +4,7 @@ import { mediaResultSchema } from "./media-operation-contract.js";
4
4
  import { pendingSchema } from "@fungi.computer/agar/backend-definition";
5
5
  import { mediaFailureSchema } from "./browser-failure.js";
6
6
  /** Bounded catalog decoded by the App media broker before host filtering. */
7
- export const mediaModelsSchema = z
8
- .array(mediaModelSchema)
9
- .max(listMediaModels().length);
7
+ export const mediaModelsSchema = z.lazy(() => z.array(mediaModelSchema).max(listMediaModels().length));
10
8
  /** An absolute output path on the Computer admitted by the App host. */
11
9
  export const destinationSchema = z.strictObject({
12
10
  /** Computer admitted by the host. */
@@ -36,14 +34,14 @@ export const appMediaAdmissionErrorSchema = z.strictObject({
36
34
  }),
37
35
  });
38
36
  /** Attachment budget refusal emitted by the Media reservation owner. */
39
- export const appMediaBudgetRefusalSchema = z.strictObject({
37
+ export const appMediaBudgetRefusalSchema = z.lazy(() => z.strictObject({
40
38
  /** The attachment's operation budget refused this request. */
41
39
  error: z.literal("attachment_budget_exceeded"),
42
40
  /** Media reservations use the Media budget, not exec or write. */
43
41
  kind: z.literal("media"),
44
42
  /** Delay emitted by the reservation owner. */
45
43
  retryAfterMs: z.number(),
46
- });
44
+ }));
47
45
  /** Existing Media admission refusals, without an admitted selector or callable. */
48
46
  export const appMediaAdmissionRefusalSchema = z.union([
49
47
  appMediaAdmissionErrorSchema,
@@ -61,12 +59,12 @@ export const appMediaBrokerErrorSchema = appMediaAdmissionErrorSchema.extend({
61
59
  }),
62
60
  });
63
61
  /** Missing-library refusal decoded and returned by the App media broker. */
64
- export const agentAppMediaLibraryFailureSchema = z.strictObject({
62
+ export const agentAppMediaLibraryFailureSchema = z.lazy(() => z.strictObject({
65
63
  /** The calling Installation's library is unavailable. */
66
64
  error: z.literal("library_unavailable"),
67
65
  /** Existing library-owner presentation copy. */
68
66
  message: z.string().max(4096),
69
- });
67
+ }));
70
68
  /** Broker projection of an HTTP failure: code becomes error and error becomes message. */
71
69
  export const appMediaBrokerFailureSchema = z.strictObject({
72
70
  /** Original typed HTTP failure code. */
@@ -77,6 +75,8 @@ export const appMediaBrokerFailureSchema = z.strictObject({
77
75
  stage: mediaFailureSchema.shape.stage,
78
76
  /** Original retry truth. */
79
77
  retryable: mediaFailureSchema.shape.retryable,
78
+ /** Original bounded provider facts, when available. */
79
+ provider: mediaFailureSchema.shape.provider,
80
80
  });
81
81
  /** Refusal payloads emitted by the App media broker, separate from transport errors. */
82
82
  export const appMediaRefusalSchema = z.union([
@@ -33,6 +33,13 @@ export declare const mediaFailureSchema: z.ZodObject<{
33
33
  readonly SAFETY_FILTER_REFUSED: "SAFETY_FILTER_REFUSED";
34
34
  }>;
35
35
  retryable: z.ZodBoolean;
36
+ provider: z.ZodOptional<z.ZodPipe<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodTransform<Readonly<{
37
+ category: "InferenceUpstreamError" | "AiInternalError" | "TypeError" | "AbortError" | "TimeoutError" | "Error";
38
+ code: number | null;
39
+ }> | Readonly<{
40
+ category: "result_download";
41
+ status: number;
42
+ }>, unknown>>>;
36
43
  }, z.core.$strict>;
37
44
  /** Sanitized Media failure carried from the authenticated host to Agar. */
38
45
  export type MediaFailure = z.output<typeof mediaFailureSchema>;
@@ -2,6 +2,7 @@ import * as z from "zod";
2
2
  import { mediaFailureStageSchema } from "./execution-error.js";
3
3
  import { Option, Schema } from "effect";
4
4
  import { reportCatchFailure } from "./failure.js";
5
+ import { mediaProviderDiagnosticWireSchema } from "@fungi.computer/agar/errors";
5
6
  /** Sanitized HTTP refusal emitted by a Media host and decoded at the browser boundary. */
6
7
  export const mediaFailureSchema = z.strictObject({
7
8
  /** Host-supplied presentation copy. */
@@ -23,6 +24,8 @@ export const mediaFailureSchema = z.strictObject({
23
24
  }),
24
25
  /** Whether repeating this exact attempt may recover. */
25
26
  retryable: z.boolean(),
27
+ /** Allowlisted provider facts only; the original cause never crosses HTTP. */
28
+ provider: mediaProviderDiagnosticWireSchema.optional(),
26
29
  });
27
30
  const decodeJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json));
28
31
  function parseMediaFailureJson(json) {
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import * as Redacted from "effect/Redacted";
3
3
  import { buildProviderInput, getMediaModel, estimateImageMilliunits, normalizeMediaProviderOutput, mediaProviderWireSchema, } from "../index.js";
4
4
  import { MediaExecutionError, MediaSafetyFilterRefusal, } from "../execution-error.js";
5
+ import { decodeMediaProviderErrorCategory, } from "@fungi.computer/agar/errors";
5
6
  import { estimateGatewayMilliunits, gatewayInput, isGatewayModel, } from "../gateway-models.js";
6
7
  import { GATEWAY_VIDEO_MAX_BYTES, gatewayOutputSchema, isMp4, } from "../gateway-wire.js";
7
8
  import { videoProviderAdapters } from "../video-providers/index.js";
@@ -25,31 +26,21 @@ export function estimate(settings, references) {
25
26
  }
26
27
  // Workers AI prefixes upstream error messages with its numeric internal code.
27
28
  // Parse only that bounded identifier; the remaining message is never logged.
28
- const providerFailureCode = z
29
+ const providerFailureCode = z.lazy(() => z
29
30
  .string()
30
31
  .regex(/^\d{4,5}: /u)
31
32
  .transform((message) => Number(message.split(":", 1)[0]))
32
33
  .nullable()
33
- .catch(null);
34
- const providerFailureCategory = z
35
- .enum([
36
- "InferenceUpstreamError",
37
- "AiInternalError",
38
- "TypeError",
39
- "AbortError",
40
- "TimeoutError",
41
- "Error",
42
- ])
43
- .catch("Error");
34
+ .catch(null));
44
35
  // Recognize the refusal, not the generic Workers AI error number or prompt text.
45
- const safetyFilterMessage = z.union([
36
+ const safetyFilterMessage = z.lazy(() => z.union([
46
37
  z
47
38
  .string()
48
39
  .regex(/(?:^|:\s)(?:AiError:\s)?Input prompt contains NSFW content\b/iu),
49
40
  // Veo's documented input-policy refusal; keep its details private as well.
50
41
  // https://docs.cloud.google.com/vertex-ai/generative-ai/docs/video/responsible-ai-and-usage-guidelines
51
42
  z.string().regex(/\bit might violate our policies\b/iu),
52
- ]);
43
+ ]));
53
44
  /** Encode multipart once with the platform's boundary, as required by AI.run. */
54
45
  function workersAiInput(payload) {
55
46
  if (payload.transport === "json")
@@ -64,17 +55,21 @@ function workersAiInput(payload) {
64
55
  }
65
56
  /** Retain the original provider failure alongside its bounded code and category. */
66
57
  function providerFailure(model, cause) {
58
+ const provider = {
59
+ category: decodeMediaProviderErrorCategory(cause instanceof Error ? cause.name : undefined),
60
+ code: providerFailureCode.parse(cause instanceof Error ? cause.message : undefined),
61
+ };
67
62
  // Workers correlates this structured event with the request trace. Never log
68
63
  // the provider message/body: either can contain customer prompt content.
69
64
  console.error("Media provider request failed", {
70
65
  model,
71
- providerCode: providerFailureCode.parse(cause instanceof Error ? cause.message : undefined),
72
- category: providerFailureCategory.parse(cause instanceof Error ? cause.name : undefined),
66
+ providerCode: provider.code,
67
+ category: provider.category,
73
68
  }, Redacted.make(cause));
74
69
  return cause instanceof Error &&
75
70
  safetyFilterMessage.safeParse(cause.message).success
76
- ? new MediaSafetyFilterRefusal({ cause })
77
- : new MediaExecutionError("provider", { cause });
71
+ ? new MediaSafetyFilterRefusal({ cause, provider })
72
+ : new MediaExecutionError("provider", { cause, provider });
78
73
  }
79
74
  /** Run a gateway model and fetch its result URL within the byte bound. */
80
75
  async function generateThroughGateway(ai, settings, references, signal, options, fetchResult, outputFormat) {
@@ -95,7 +90,9 @@ async function generateThroughGateway(ai, settings, references, signal, options,
95
90
  const url = videoProviderAdapters[model.video.provider].decodeResultUrl(providerValue);
96
91
  const response = await fetchResult(url, { signal: signal ?? null });
97
92
  if (!response.ok)
98
- throw new Error("gateway video result unavailable");
93
+ throw new MediaExecutionError("normalization", {
94
+ provider: { category: "result_download", status: response.status },
95
+ });
99
96
  const bytes = await readResponseBytes(response, GATEWAY_VIDEO_MAX_BYTES);
100
97
  if (!isMp4(bytes))
101
98
  throw new Error("gateway video is not an MP4");
@@ -107,6 +104,8 @@ async function generateThroughGateway(ai, settings, references, signal, options,
107
104
  }), { fetchUrl: (url) => fetchResult(url, { signal: signal ?? null }) });
108
105
  }
109
106
  catch (cause) {
107
+ if (cause instanceof MediaExecutionError)
108
+ throw cause;
110
109
  throw new MediaExecutionError("normalization", { cause });
111
110
  }
112
111
  }
@@ -2,11 +2,11 @@ import { z } from "zod";
2
2
  import { MAX_REFERENCE_BYTES, MAX_REFERENCE_DIMENSION, MediaSettingsError, viewDimensionSchema, } from "../index.js";
3
3
  /** The retained `read_image` encoding: JPEG at quality 80. */
4
4
  const VIEW_JPEG_QUALITY = 80;
5
- const metadata = z.object({
5
+ const metadata = z.lazy(() => z.object({
6
6
  format: z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]),
7
7
  width: z.number().int().positive(),
8
8
  height: z.number().int().positive(),
9
- });
9
+ }));
10
10
  const formats = {
11
11
  "image/png": "png",
12
12
  "image/jpeg": "jpeg",
@@ -4,7 +4,7 @@ import * as z from "zod";
4
4
  const TILE = 512;
5
5
  const MAX_DIMENSION = 4_096;
6
6
  const MAX_REFERENCES = 4;
7
- const imageParamsSchema = z
7
+ const imageParamsSchema = z.lazy(() => z
8
8
  .object({
9
9
  width: z.number().int().min(1).max(MAX_DIMENSION),
10
10
  height: z.number().int().min(1).max(MAX_DIMENSION),
@@ -19,7 +19,7 @@ const imageParamsSchema = z
19
19
  .max(MAX_REFERENCES)
20
20
  .optional(),
21
21
  })
22
- .strict();
22
+ .strict());
23
23
  const invalid = (message) => {
24
24
  throw new MediaSettingsError(`image cost parameters are invalid: ${message}`);
25
25
  };
@@ -1,4 +1,5 @@
1
1
  import * as z from "zod";
2
+ import { type MediaProviderDiagnostic } from "@fungi.computer/agar/errors";
2
3
  /** Public diagnostic labels only; never provider messages or request data. */
3
4
  export declare const mediaFailureStageSchema: z.ZodEnum<{
4
5
  /** Host admission before operation creation. */
@@ -26,17 +27,24 @@ export declare const mediaFailureStageSchema: z.ZodEnum<{
26
27
  }>;
27
28
  /** Execution stage at which a generation failed. */
28
29
  export type MediaFailureStage = Exclude<z.output<typeof mediaFailureStageSchema>, "admission" | "settings">;
30
+ /** Private cause plus an independently decoded, safe provider diagnostic. */
31
+ export type MediaExecutionErrorOptions = ErrorOptions & {
32
+ /** Safe provider facts, when the failure came from provider transport. */
33
+ readonly provider?: MediaProviderDiagnostic | undefined;
34
+ };
29
35
  /** A bounded stage marker for failures that cross the Media HTTP boundary. */
30
36
  export declare class MediaExecutionError extends Error {
31
37
  /** Execution stage where the failure occurred. */
32
38
  readonly stage: MediaFailureStage;
39
+ /** Safe provider facts only; the original cause remains private. */
40
+ readonly provider: MediaProviderDiagnostic | undefined;
33
41
  constructor(
34
42
  /** Execution stage where the failure occurred. */
35
- stage: MediaFailureStage, options?: ErrorOptions);
43
+ stage: MediaFailureStage, options?: MediaExecutionErrorOptions);
36
44
  }
37
45
  /** A provider safety filter refused generation; no output was delivered. */
38
46
  export declare class MediaSafetyFilterRefusal extends MediaExecutionError {
39
- constructor(options?: ErrorOptions);
47
+ constructor(options?: MediaExecutionErrorOptions);
40
48
  }
41
49
  /** Why the host's billing owner refused to admit a new generation. */
42
50
  export type MediaBillingRefusalCode = "insufficient_credits" | "daily_limit_reached" | "denied";
@@ -1,4 +1,5 @@
1
1
  import * as z from "zod";
2
+ import { decodeMediaProviderDiagnostic, } from "@fungi.computer/agar/errors";
2
3
  /** Public diagnostic labels only; never provider messages or request data. */
3
4
  export const mediaFailureStageSchema = z.enum({
4
5
  /** Host admission before operation creation. */
@@ -27,12 +28,18 @@ export const mediaFailureStageSchema = z.enum({
27
28
  /** A bounded stage marker for failures that cross the Media HTTP boundary. */
28
29
  export class MediaExecutionError extends Error {
29
30
  stage;
31
+ /** Safe provider facts only; the original cause remains private. */
32
+ provider;
30
33
  constructor(
31
34
  /** Execution stage where the failure occurred. */
32
35
  stage, options) {
33
36
  super(`Media ${stage} failed`, options);
34
37
  this.stage = stage;
35
38
  this.name = "MediaExecutionError";
39
+ this.provider =
40
+ options?.provider === undefined
41
+ ? undefined
42
+ : decodeMediaProviderDiagnostic(options.provider);
36
43
  }
37
44
  }
38
45
  /** A provider safety filter refused generation; no output was delivered. */
@@ -1,15 +1,15 @@
1
1
  import { z } from "zod";
2
2
  /** A result URL every gateway provider must return as plain HTTPS. */
3
- export declare const resultUrl: z.ZodURL;
3
+ export declare const resultUrl: z.ZodLazy<z.ZodURL>;
4
4
  /** The Unified AI gateway's normalized answer: a completed state and one
5
5
  * result URL. Seedance and Veo answer this way; MiniMax does not. */
6
- export declare const gatewayOutputSchema: z.ZodObject<{
6
+ export declare const gatewayOutputSchema: z.ZodLazy<z.ZodObject<{
7
7
  state: z.ZodOptional<z.ZodLiteral<"Completed">>;
8
8
  result: z.ZodObject<{
9
- image: z.ZodOptional<z.ZodURL>;
10
- video: z.ZodOptional<z.ZodURL>;
9
+ image: z.ZodOptional<z.ZodLazy<z.ZodURL>>;
10
+ video: z.ZodOptional<z.ZodLazy<z.ZodURL>>;
11
11
  }, z.core.$loose>;
12
- }, z.core.$loose>;
12
+ }, z.core.$loose>>;
13
13
  /** Byte ceilings for fetched results; video stays within Worker memory. */
14
14
  export declare const GATEWAY_VIDEO_MAX_BYTES: number;
15
15
  /** An MP4 carries an `ftyp` box at byte 4. */
@@ -1,17 +1,17 @@
1
1
  import { z } from "zod";
2
2
  /** A result URL every gateway provider must return as plain HTTPS. */
3
- export const resultUrl = z
3
+ export const resultUrl = z.lazy(() => z
4
4
  .url()
5
- .refine((value) => value.startsWith("https://"), "result URLs must be HTTPS");
5
+ .refine((value) => value.startsWith("https://"), "result URLs must be HTTPS"));
6
6
  /** The Unified AI gateway's normalized answer: a completed state and one
7
7
  * result URL. Seedance and Veo answer this way; MiniMax does not. */
8
- export const gatewayOutputSchema = z.looseObject({
8
+ export const gatewayOutputSchema = z.lazy(() => z.looseObject({
9
9
  state: z.literal("Completed").optional(),
10
10
  result: z.looseObject({
11
11
  image: resultUrl.optional(),
12
12
  video: resultUrl.optional(),
13
13
  }),
14
- });
14
+ }));
15
15
  /** Byte ceilings for fetched results; video stays within Worker memory. */
16
16
  export const GATEWAY_VIDEO_MAX_BYTES = 64 * 1024 * 1024;
17
17
  /** An MP4 carries an `ftyp` box at byte 4. */