@cat-factory/kernel 0.283.0 → 0.285.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 (37) hide show
  1. package/dist/domain/design-image-delivery.d.ts +128 -0
  2. package/dist/domain/design-image-delivery.d.ts.map +1 -0
  3. package/dist/domain/design-image-delivery.js +83 -0
  4. package/dist/domain/design-image-delivery.js.map +1 -0
  5. package/dist/domain/harness-capabilities.d.ts +7 -5
  6. package/dist/domain/harness-capabilities.d.ts.map +1 -1
  7. package/dist/domain/harness-capabilities.js +28 -8
  8. package/dist/domain/harness-capabilities.js.map +1 -1
  9. package/dist/domain/models.d.ts +2 -0
  10. package/dist/domain/models.d.ts.map +1 -1
  11. package/dist/domain/models.js +68 -11
  12. package/dist/domain/models.js.map +1 -1
  13. package/dist/domain/types.d.ts +40 -0
  14. package/dist/domain/types.d.ts.map +1 -1
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/ports/agent-executor.d.ts +39 -8
  20. package/dist/ports/agent-executor.d.ts.map +1 -1
  21. package/dist/ports/agent-executor.js.map +1 -1
  22. package/dist/ports/model-provider.d.ts +14 -0
  23. package/dist/ports/model-provider.d.ts.map +1 -1
  24. package/dist/ports/model-provider.js.map +1 -1
  25. package/dist/ports/pr-mergeability.d.ts +9 -1
  26. package/dist/ports/pr-mergeability.d.ts.map +1 -1
  27. package/dist/ports/pr-merger.d.ts +5 -2
  28. package/dist/ports/pr-merger.d.ts.map +1 -1
  29. package/dist/ports/pr-report.d.ts +10 -3
  30. package/dist/ports/pr-report.d.ts.map +1 -1
  31. package/dist/ports/runner-transport.d.ts +5 -1
  32. package/dist/ports/runner-transport.d.ts.map +1 -1
  33. package/dist/shared/redact-image-payloads.logic.d.ts +14 -0
  34. package/dist/shared/redact-image-payloads.logic.d.ts.map +1 -0
  35. package/dist/shared/redact-image-payloads.logic.js +100 -0
  36. package/dist/shared/redact-image-payloads.logic.js.map +1 -0
  37. package/package.json +2 -2
@@ -0,0 +1,128 @@
1
+ import type { HarnessKind, ModelRef } from '../ports/model-provider.js';
2
+ /**
3
+ * Which harnesses can put an IMAGE in front of their model, as an exhaustive `Record` over
4
+ * `HarnessKind` so a new harness cannot be added without stating its answer (an omitted entry
5
+ * would read as `false` and silently drop every render on that harness).
6
+ *
7
+ * `false` is a statement about THIS repo's pinned CLI, not a claim about the vendor's product. The
8
+ * bar for `true` is that the image has a verified way to get bytes into a turn, because the cost of
9
+ * guessing is asymmetric: a harness wrongly marked `true` is handed a manifest, downloads the
10
+ * frames, tells the agent they are there, and the agent then reports it cannot see them, which
11
+ * reads to everyone as a platform bug rather than as a missing capability. A harness wrongly marked
12
+ * `false` costs a run the pictures and SAYS SO, which is the disposition the whole vocabulary
13
+ * below exists to give.
14
+ *
15
+ * - `claude-code` reads an image file with its own file-reading tool, which is why the container
16
+ * half of this feature is files on disk plus a prompt that names them: the CLI composes the
17
+ * image content part, exactly as it does for a screenshot a human pastes at it.
18
+ * - `codex` and `pi` are `false` today. Codex's pinned CLI has no verified file-to-turn path in
19
+ * this image, and Pi has no image input at all (the same reason it has no MCP client). Flip an
20
+ * entry here in the change that teaches the image to carry the bytes, never ahead of it.
21
+ */
22
+ export declare const HARNESS_IMAGE_INPUT: Record<HarnessKind, boolean>;
23
+ /**
24
+ * Whether this harness can open an image file the platform wrote into the checkout.
25
+ *
26
+ * TOTAL over `HarnessKind`, with no "no harness" case: an inline call has no CLI to ask about, and
27
+ * letting `undefined` answer `true` here is what once let the ambient inline path (a harness CLI
28
+ * fed one-shot text) inherit the container answer and promise files nothing wrote. Which channel a
29
+ * site has is {@link DesignImageCarrier}'s job to state, not this table's to guess.
30
+ */
31
+ export declare function harnessAcceptsImages(harness: HarnessKind): boolean;
32
+ /**
33
+ * Why a run's design renders were NOT put in front of its model.
34
+ *
35
+ * Each member names a DIFFERENT fix, which is why they are not folded into one "unavailable":
36
+ *
37
+ * - `harness_no_image_input` is the CLI: this kind runs in a container on a harness with no way to
38
+ * read an image into a turn. Switching the step's model to another image-capable one changes
39
+ * nothing; the fix is a different harness (or an image that teaches this one).
40
+ * - `model_no_image_input` is the model: the harness could carry an image and the resolved model
41
+ * does not take one. Here the fix IS the model, which is why it must not read as the harness's
42
+ * limitation.
43
+ * - `unknown_model_image_input` is the honest third answer, and the commonest: the catalog does not
44
+ * declare whether this flavour accepts images. It is kept apart from `model_no_image_input`
45
+ * because they send a reader to opposite places (declare the capability, versus pick a different
46
+ * model), and collapsing them would let an undeclared multimodal model read as a text-only one
47
+ * forever, with nothing anywhere saying the platform simply never asked.
48
+ * - `transfer_failed` is the store: the pair CAN carry an image and the bytes did not arrive. The
49
+ * only transient member, and the only one worth retrying.
50
+ *
51
+ * Two more name a SEAM that carries no picture whatever the harness and the model could do, so
52
+ * neither comes out of {@link resolveDesignImageDelivery}: there is no pair to join, and the site
53
+ * that knows which seam it is states it directly, exactly as the store's own failure does.
54
+ *
55
+ * - `inline_harness_text_only` is the ambient inline path: the deployment serves a subscription ref
56
+ * by driving its CLI as a host subprocess with one-shot text on stdin. It names a harness whose
57
+ * container dispatch reads image files perfectly well, and has neither a checkout to write one
58
+ * into nor a message part to attach. The fix is a deployment's, not a run's: serve this kind
59
+ * somewhere that has one.
60
+ * - `consensus_panel` is a diverted step: its participants share ONE composed prompt string across
61
+ * models that need not agree about image input, so there is nothing to attach a picture to. Named
62
+ * for the surface rather than for a capability, and spelled to match the `UnavailableToolServer`
63
+ * reason a panel already reports for the same reason on the same surface.
64
+ *
65
+ * There is deliberately no member for "the task has no design": that is an absent set, not a
66
+ * refused delivery, and a run with nothing to show must not tell its agent that something was
67
+ * withheld.
68
+ */
69
+ export type DesignImageUnavailableReason = 'harness_no_image_input' | 'model_no_image_input' | 'unknown_model_image_input' | 'inline_harness_text_only' | 'consensus_panel' | 'transfer_failed';
70
+ /**
71
+ * HOW the pictures reached the model, when they did.
72
+ *
73
+ * Carried rather than re-derived at each prompt site, because the two channels put the images in
74
+ * different places and a prompt that names the wrong one is worse than one that names neither: a
75
+ * container agent told its designs are "attached below" goes looking through a message that has
76
+ * none, and an inline model pointed at a checkout directory has no filesystem to look in.
77
+ *
78
+ * - `files` — the harness wrote them into the checkout and the CLI reads them with its own
79
+ * image-reading tool, which is what composes the image content part.
80
+ * - `message` — the caller put them in the model request itself, as image parts (an inline call:
81
+ * there is no CLI in between and no disk to write to).
82
+ */
83
+ export type DesignImageChannel = 'files' | 'message';
84
+ /**
85
+ * What a dispatch decided about its renders: a discriminated result rather than a nullable one, so
86
+ * "not attached" always arrives WITH its cause and the prompt can state it.
87
+ */
88
+ export type DesignImageDelivery = {
89
+ attached: true;
90
+ channel: DesignImageChannel;
91
+ } | {
92
+ attached: false;
93
+ reason: DesignImageUnavailableReason;
94
+ };
95
+ /**
96
+ * The route a dispatch site has for putting bytes in front of its model: the half of the decision
97
+ * that is a property of the SEAM rather than of the model.
98
+ *
99
+ * Declared by the site because only the site knows it. "Is a harness named" does not answer it (the
100
+ * ambient inline path names one and can carry nothing), and neither does "is this call inline" (a
101
+ * consensus panel is inline and can carry nothing either). A site with no route at all does not
102
+ * build a carrier: it states its own refusal from the two seam reasons above.
103
+ */
104
+ export type DesignImageCarrier =
105
+ /** A container dispatch: the harness downloads the files and its CLI opens them. */
106
+ {
107
+ channel: 'files';
108
+ harness: HarnessKind;
109
+ }
110
+ /** An inline model call composing its own request, so it can add image parts itself. */
111
+ | {
112
+ channel: 'message';
113
+ };
114
+ /**
115
+ * Join the two halves for one dispatch: the carrier's ability to carry an image and the resolved
116
+ * model's ability to take one.
117
+ *
118
+ * The carrier is asked FIRST, and the order is load-bearing rather than stylistic. A subscription
119
+ * harness pins its own model, so a Codex run reporting `model_no_image_input` would send someone to
120
+ * change a model they cannot change without also changing the harness; the CLI is the outer
121
+ * constraint and the honest one to name.
122
+ *
123
+ * `acceptsImages` is a tri-state on purpose (see {@link DesignImageUnavailableReason}): `true`
124
+ * attaches, `false` refuses as the model's limitation, and ABSENT refuses as the platform's own
125
+ * silence about this flavour.
126
+ */
127
+ export declare function resolveDesignImageDelivery(carrier: DesignImageCarrier, ref: Pick<ModelRef, 'acceptsImages'>): DesignImageDelivery;
128
+ //# sourceMappingURL=design-image-delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-image-delivery.d.ts","sourceRoot":"","sources":["../../src/domain/design-image-delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAA;AAyBvE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAI5D,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,4BAA4B,GACpC,wBAAwB,GACxB,sBAAsB,GACtB,2BAA2B,GAC3B,0BAA0B,GAC1B,iBAAiB,GACjB,iBAAiB,CAAA;AAErB;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,GAC/C;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,4BAA4B,CAAA;CAAE,CAAA;AAE7D;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB;AAC5B,oFAAoF;AAClF;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE;AAC5C,wFAAwF;GACtF;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,CAAA;AAE1B;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,GACnC,mBAAmB,CASrB"}
@@ -0,0 +1,83 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Whether a dispatch can put a design RENDER in front of its model, and the reason when it
3
+ // cannot.
4
+ //
5
+ // The platform holds pictures of a task's linked designs (the frames an import retained, plus the
6
+ // images a person attached), and until now they reached a model on no path at all: a container
7
+ // agent got the textual `.cat-context/` description and an explicit instruction NOT to fetch the
8
+ // preview URL, and an inline caller got the same text. What a designer actually cares about, what
9
+ // the screen looks like, was invisible to every agent building it.
10
+ //
11
+ // Delivery is a PAIR fact, and both halves have to be true: the dispatch site must have a CHANNEL
12
+ // that can carry bytes to the model, and the model must accept them. Neither half implies the
13
+ // other, so they are declared separately and joined here, once, rather than re-derived at each
14
+ // delivery site.
15
+ //
16
+ // The channel is stated BY the call site rather than inferred from "is there a harness", because
17
+ // the two are not the same question and the sites where they disagree are exactly the ones that
18
+ // break silently. An ambient inline run drives a harness CLI with one-shot text on stdin: it names
19
+ // a harness, has no checkout to write a file into, and flattens its message to a string, so it can
20
+ // carry a picture by neither route. A consensus panel is inline with no harness at all and still
21
+ // cannot carry one, because its participants share a single composed prompt string.
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Which harnesses can put an IMAGE in front of their model, as an exhaustive `Record` over
25
+ * `HarnessKind` so a new harness cannot be added without stating its answer (an omitted entry
26
+ * would read as `false` and silently drop every render on that harness).
27
+ *
28
+ * `false` is a statement about THIS repo's pinned CLI, not a claim about the vendor's product. The
29
+ * bar for `true` is that the image has a verified way to get bytes into a turn, because the cost of
30
+ * guessing is asymmetric: a harness wrongly marked `true` is handed a manifest, downloads the
31
+ * frames, tells the agent they are there, and the agent then reports it cannot see them, which
32
+ * reads to everyone as a platform bug rather than as a missing capability. A harness wrongly marked
33
+ * `false` costs a run the pictures and SAYS SO, which is the disposition the whole vocabulary
34
+ * below exists to give.
35
+ *
36
+ * - `claude-code` reads an image file with its own file-reading tool, which is why the container
37
+ * half of this feature is files on disk plus a prompt that names them: the CLI composes the
38
+ * image content part, exactly as it does for a screenshot a human pastes at it.
39
+ * - `codex` and `pi` are `false` today. Codex's pinned CLI has no verified file-to-turn path in
40
+ * this image, and Pi has no image input at all (the same reason it has no MCP client). Flip an
41
+ * entry here in the change that teaches the image to carry the bytes, never ahead of it.
42
+ */
43
+ export const HARNESS_IMAGE_INPUT = {
44
+ pi: false,
45
+ 'claude-code': true,
46
+ codex: false,
47
+ };
48
+ /**
49
+ * Whether this harness can open an image file the platform wrote into the checkout.
50
+ *
51
+ * TOTAL over `HarnessKind`, with no "no harness" case: an inline call has no CLI to ask about, and
52
+ * letting `undefined` answer `true` here is what once let the ambient inline path (a harness CLI
53
+ * fed one-shot text) inherit the container answer and promise files nothing wrote. Which channel a
54
+ * site has is {@link DesignImageCarrier}'s job to state, not this table's to guess.
55
+ */
56
+ export function harnessAcceptsImages(harness) {
57
+ return HARNESS_IMAGE_INPUT[harness];
58
+ }
59
+ /**
60
+ * Join the two halves for one dispatch: the carrier's ability to carry an image and the resolved
61
+ * model's ability to take one.
62
+ *
63
+ * The carrier is asked FIRST, and the order is load-bearing rather than stylistic. A subscription
64
+ * harness pins its own model, so a Codex run reporting `model_no_image_input` would send someone to
65
+ * change a model they cannot change without also changing the harness; the CLI is the outer
66
+ * constraint and the honest one to name.
67
+ *
68
+ * `acceptsImages` is a tri-state on purpose (see {@link DesignImageUnavailableReason}): `true`
69
+ * attaches, `false` refuses as the model's limitation, and ABSENT refuses as the platform's own
70
+ * silence about this flavour.
71
+ */
72
+ export function resolveDesignImageDelivery(carrier, ref) {
73
+ if (carrier.channel === 'files' && !harnessAcceptsImages(carrier.harness)) {
74
+ return { attached: false, reason: 'harness_no_image_input' };
75
+ }
76
+ if (ref.acceptsImages === undefined) {
77
+ return { attached: false, reason: 'unknown_model_image_input' };
78
+ }
79
+ if (!ref.acceptsImages)
80
+ return { attached: false, reason: 'model_no_image_input' };
81
+ return { attached: true, channel: carrier.channel };
82
+ }
83
+ //# sourceMappingURL=design-image-delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-image-delivery.js","sourceRoot":"","sources":["../../src/domain/design-image-delivery.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,2FAA2F;AAC3F,UAAU;AACV,EAAE;AACF,kGAAkG;AAClG,+FAA+F;AAC/F,iGAAiG;AACjG,kGAAkG;AAClG,mEAAmE;AACnE,EAAE;AACF,kGAAkG;AAClG,8FAA8F;AAC9F,+FAA+F;AAC/F,iBAAiB;AACjB,EAAE;AACF,iGAAiG;AACjG,gGAAgG;AAChG,mGAAmG;AACnG,mGAAmG;AACnG,iGAAiG;AACjG,oFAAoF;AACpF,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAiC;IAC/D,EAAE,EAAE,KAAK;IACT,aAAa,EAAE,IAAI;IACnB,KAAK,EAAE,KAAK;CACb,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAoB;IACvD,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAA;AACrC,CAAC;AAqFD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA2B,EAC3B,GAAoC;IAEpC,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1E,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAA;IAC9D,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAA;IACjE,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,aAAa;QAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAA;IAClF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;AACrD,CAAC"}
@@ -7,13 +7,19 @@ import type { RunnerDispatchAck, RunnerJobStopOutcome } from '../ports/runner-tr
7
7
  * (`packageRegistries`, `validation`) needs no handshake, because an older image simply does less and
8
8
  * the run reports what it did. Adding a member here is a claim that the PROMPT would lie.
9
9
  *
10
+ * That is also why `designImages` is a member and `referenceScreenshots` is not, though they are the
11
+ * same wire shape: the capture block is composed BY the harness out of what actually landed, so an
12
+ * image that ignores the field simply says nothing, while the design block is composed by the
13
+ * BACKEND (only it knows the delivery verdict and the views no container was sent) and would name a
14
+ * directory an older image never wrote.
15
+ *
10
16
  * Keyed as an exhaustive `Record` so the list below cannot drift from the union, and mirrored
11
17
  * byte-for-byte by the harness's own `HARNESS_BODY_CAPABILITIES` (the image is built from `src/`
12
18
  * plus typescript alone, so it can depend on no workspace package). The pairing is pinned by the
13
19
  * harness's `test/agent-capabilities.conformity.test.ts`, the same copy-plus-pin arrangement the
14
20
  * id/tool-name patterns use.
15
21
  */
16
- export type HarnessBodyCapability = 'mcpServers' | 'skills';
22
+ export type HarnessBodyCapability = 'mcpServers' | 'skills' | 'designImages';
17
23
  /** Every capability the handshake covers. Derived, so it cannot drift from the union. */
18
24
  export declare const HARNESS_BODY_CAPABILITIES: HarnessBodyCapability[];
19
25
  /** What a capability is, for an operator-facing message. */
@@ -41,10 +47,6 @@ export declare function parseHarnessBodyCapabilities(value: unknown): HarnessBod
41
47
  * dropped every tool server for its own reasons (an unsupported harness, a missing credential)
42
48
  * promised the agent nothing and has nothing to verify. What must line up is the body and the
43
49
  * PROMPT, and the prompt is composed from the same resolution the body is.
44
- *
45
- * A capability's name IS its body field name, deliberately. That is what lets this stay one
46
- * filter instead of a second mapping to keep in step, and it is why the harness's own list is a
47
- * list of field names too.
48
50
  */
49
51
  export declare function requiredHarnessCapabilities(body: Readonly<Record<string, unknown>>): HarnessBodyCapability[];
50
52
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"harness-capabilities.d.ts","sourceRoot":"","sources":["../../src/domain/harness-capabilities.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAE3F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,QAAQ,CAAA;AAQ3D,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,EAEjC,qBAAqB,EAAE,CAAA;AAE5B,4DAA4D;AAC5D,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,qBAAqB,GAAG,MAAM,CAEvF;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAItF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,EAAE,GAAG,SAAS,CAGhG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,qBAAqB,EAAE,CAKzB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAMlF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAA;AAE7D,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,EAC1C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,GAAG,SAAS,GACrD,wBAAwB,CAK1B;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG,QAAQ,CAAA;AAmCjE;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAQR"}
1
+ {"version":3,"file":"harness-capabilities.d.ts","sourceRoot":"","sources":["../../src/domain/harness-capabilities.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAE3F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,QAAQ,GAAG,cAAc,CAAA;AAS5E,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,EAEjC,qBAAqB,EAAE,CAAA;AAE5B,4DAA4D;AAC5D,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,qBAAqB,GAAG,MAAM,CAEvF;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAItF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,EAAE,GAAG,SAAS,CAGhG;AAgCD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,qBAAqB,EAAE,CAIzB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,GAAG,SAAS,CAMlF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,qBAAqB,EAAE,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAA;AAE7D,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,EAC1C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,GAAG,SAAS,GACrD,wBAAwB,CAK1B;AAED;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG,QAAQ,CAAA;AAmCjE;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAQR"}
@@ -19,6 +19,7 @@
19
19
  const HARNESS_BODY_CAPABILITY_LABELS = {
20
20
  mcpServers: 'tool servers (MCP)',
21
21
  skills: 'skills',
22
+ designImages: 'design pictures',
22
23
  };
23
24
  /** Every capability the handshake covers. Derived, so it cannot drift from the union. */
24
25
  export const HARNESS_BODY_CAPABILITIES = Object.keys(HARNESS_BODY_CAPABILITY_LABELS);
@@ -48,6 +49,32 @@ export function parseHarnessBodyCapabilities(value) {
48
49
  return undefined;
49
50
  return value.filter(isHarnessBodyCapability);
50
51
  }
52
+ /** A non-empty array: the wire shape of every capability that is simply a list. */
53
+ function isPopulatedList(value) {
54
+ return Array.isArray(value) && value.length > 0;
55
+ }
56
+ /**
57
+ * What "the body carries this capability" means for each one, as an exhaustive `Record` so a new
58
+ * member cannot be added without stating its own answer.
59
+ *
60
+ * A predicate per capability rather than one shape test over all of them, because the field shapes
61
+ * genuinely differ and the wrong generalisation is SILENT in the worst direction: `designImages` is
62
+ * an object (`{ url, token, files }`), so the populated-list test every list-shaped capability
63
+ * shares reads it as absent, the handshake never fires for it, and an image that predates the field
64
+ * ignores the manifest while the backend's prompt names a directory nothing wrote. That is
65
+ * precisely the blind run this whole handshake exists to refuse.
66
+ *
67
+ * The KEY is still the body field name, which is what keeps the harness's own list a list of field
68
+ * names and needs no second mapping there; only the emptiness test lives here.
69
+ */
70
+ const HARNESS_BODY_CAPABILITY_CARRIED = {
71
+ mcpServers: isPopulatedList,
72
+ skills: isPopulatedList,
73
+ // A manifest with no files promises the agent nothing, exactly as an empty server list does.
74
+ designImages: (value) => typeof value === 'object' &&
75
+ value !== null &&
76
+ isPopulatedList(value.files),
77
+ };
51
78
  /**
52
79
  * Which capabilities a job body actually CARRIES, which is what the handshake is checked against.
53
80
  *
@@ -55,16 +82,9 @@ export function parseHarnessBodyCapabilities(value) {
55
82
  * dropped every tool server for its own reasons (an unsupported harness, a missing credential)
56
83
  * promised the agent nothing and has nothing to verify. What must line up is the body and the
57
84
  * PROMPT, and the prompt is composed from the same resolution the body is.
58
- *
59
- * A capability's name IS its body field name, deliberately. That is what lets this stay one
60
- * filter instead of a second mapping to keep in step, and it is why the harness's own list is a
61
- * list of field names too.
62
85
  */
63
86
  export function requiredHarnessCapabilities(body) {
64
- return HARNESS_BODY_CAPABILITIES.filter((capability) => {
65
- const value = body[capability];
66
- return Array.isArray(value) && value.length > 0;
67
- });
87
+ return HARNESS_BODY_CAPABILITIES.filter((capability) => HARNESS_BODY_CAPABILITY_CARRIED[capability](body[capability]));
68
88
  }
69
89
  /**
70
90
  * Read a harness's `POST /jobs` acceptance body into a {@link RunnerDispatchAck}.
@@ -1 +1 @@
1
- {"version":3,"file":"harness-capabilities.js","sourceRoot":"","sources":["../../src/domain/harness-capabilities.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,iGAAiG;AACjG,EAAE;AACF,6FAA6F;AAC7F,gGAAgG;AAChG,kGAAkG;AAClG,4FAA4F;AAC5F,kGAAkG;AAClG,kGAAkG;AAClG,0FAA0F;AAC1F,EAAE;AACF,4FAA4F;AAC5F,6FAA6F;AAC7F,8FAA8F;AAC9F,wFAAwF;AACxF,6FAA6F;AAC7F,4FAA4F;AAoB5F,kFAAkF;AAClF,MAAM,8BAA8B,GAA0C;IAC5E,UAAU,EAAE,oBAAoB;IAChC,MAAM,EAAE,QAAQ;CACjB,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,IAAI,CAClD,8BAA8B,CACJ,CAAA;AAE5B,4DAA4D;AAC5D,MAAM,UAAU,6BAA6B,CAAC,UAAiC;IAC7E,OAAO,8BAA8B,CAAC,UAAU,CAAC,CAAA;AACnD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAK,yBAA+C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC9F,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAuC;IAEvC,OAAO,yBAAyB,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,CAAA;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IAC/D,MAAM,YAAY,GAAI,IAAmC,CAAC,YAAY,CAAA;IACtE,OAAO,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;QAChC,CAAC,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,EAAE;QAC9F,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAoBD,MAAM,UAAU,+BAA+B,CAC7C,QAA0C,EAC1C,QAAsD;IAEtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACvD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAA;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAA;IAC/E,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;AAClF,CAAC;AASD;;;;;;;;;;GAUG;AACH,SAAS,oBAAoB,CAAC,IAAyB;IACrD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,0EAA0E,CAAA;QACnF,KAAK,WAAW;YACd,OAAO,CACL,uFAAuF;gBACvF,wDAAwD,CACzD,CAAA;QACH,KAAK,aAAa;YAChB,OAAO,CACL,sFAAsF;gBACtF,uFAAuF,CACxF,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,CACL,yFAAyF;gBACzF,kDAAkD,CACnD,CAAA;IACL,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mCAAmC,CACjD,OAAyC,EACzC,IAAyB;IAEzB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACrE,OAAO,CACL,sDAAsD,IAAI,6BAA6B;QACvF,2FAA2F;QAC3F,2FAA2F;QAC3F,oBAAoB,CAAC,IAAI,CAAC,CAC3B,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"harness-capabilities.js","sourceRoot":"","sources":["../../src/domain/harness-capabilities.ts"],"names":[],"mappings":"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"}
@@ -87,6 +87,8 @@ export interface BedrockVariant {
87
87
  baseModelId: string;
88
88
  /** Context window at Bedrock, when known (often differs from the vendor's own API). */
89
89
  contextTokens?: number;
90
+ /** Whether Bedrock serves this model with image input. See {@link ModelRef.acceptsImages}. */
91
+ acceptsImages?: boolean;
90
92
  }
91
93
  /**
92
94
  * A subscription-only variant: the model runs in the Claude Code / Codex harness
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/domain/models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/domain/models.ts"],"names":[],"mappings":"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"}
@@ -72,6 +72,7 @@ export const MODEL_CATALOG = [
72
72
  provider: 'workers-ai',
73
73
  model: '@cf/meta/llama-4-scout-17b-16e-instruct',
74
74
  contextTokens: 131_072,
75
+ acceptsImages: true,
75
76
  },
76
77
  },
77
78
  {
@@ -284,7 +285,12 @@ export const MODEL_CATALOG = [
284
285
  description: "Anthropic's most capable model — run via Claude Code on your Claude subscription, " +
285
286
  'or pay-as-you-go through OpenRouter (billed at Anthropic rates).',
286
287
  openrouter: {
287
- ref: { provider: 'openrouter', model: 'anthropic/claude-fable-5', contextTokens: 1_000_000 },
288
+ ref: {
289
+ provider: 'openrouter',
290
+ model: 'anthropic/claude-fable-5',
291
+ contextTokens: 1_000_000,
292
+ acceptsImages: true,
293
+ },
288
294
  keyEnv: 'OPENROUTER_API_KEY',
289
295
  providerLabel: 'OpenRouter',
290
296
  },
@@ -294,6 +300,7 @@ export const MODEL_CATALOG = [
294
300
  model: 'claude-fable-5',
295
301
  harness: 'claude-code',
296
302
  contextTokens: 1_000_000,
303
+ acceptsImages: true,
297
304
  },
298
305
  vendor: 'claude',
299
306
  },
@@ -306,7 +313,12 @@ export const MODEL_CATALOG = [
306
313
  'same price, run via Claude Code on your Claude subscription, or pay-as-you-go ' +
307
314
  'through OpenRouter (billed at Anthropic rates).',
308
315
  openrouter: {
309
- ref: { provider: 'openrouter', model: 'anthropic/claude-opus-5', contextTokens: 1_000_000 },
316
+ ref: {
317
+ provider: 'openrouter',
318
+ model: 'anthropic/claude-opus-5',
319
+ contextTokens: 1_000_000,
320
+ acceptsImages: true,
321
+ },
310
322
  keyEnv: 'OPENROUTER_API_KEY',
311
323
  providerLabel: 'OpenRouter',
312
324
  },
@@ -316,6 +328,7 @@ export const MODEL_CATALOG = [
316
328
  model: 'claude-opus-5',
317
329
  harness: 'claude-code',
318
330
  contextTokens: 1_000_000,
331
+ acceptsImages: true,
319
332
  },
320
333
  vendor: 'claude',
321
334
  },
@@ -332,6 +345,7 @@ export const MODEL_CATALOG = [
332
345
  model: 'claude-sonnet-5',
333
346
  harness: 'claude-code',
334
347
  contextTokens: 1_000_000,
348
+ acceptsImages: true,
335
349
  },
336
350
  vendor: 'claude',
337
351
  },
@@ -348,7 +362,7 @@ export const MODEL_CATALOG = [
348
362
  // would silently run 4.8 for a block pinned to 5. No `contextTokens`: Bedrock's window
349
363
  // for this model is per-account and we have none verified, and an invented number would
350
364
  // cap the proxy's output budget against a limit nobody measured.
351
- bedrock: { baseModelId: 'anthropic.claude-opus-4-8' },
365
+ bedrock: { baseModelId: 'anthropic.claude-opus-4-8', acceptsImages: true },
352
366
  },
353
367
  // The GPT-5.6 tiers are what Codex actually serves today: `sol` (flagship), `terra`
354
368
  // (balanced everyday) and `luna` (cheapest). The model id IS the Codex `--model` slug —
@@ -361,12 +375,23 @@ export const MODEL_CATALOG = [
361
375
  description: "OpenAI's flagship for complex coding and research — run via Codex on your ChatGPT " +
362
376
  'subscription, or pay-as-you-go through OpenRouter (billed at OpenAI rates).',
363
377
  openrouter: {
364
- ref: { provider: 'openrouter', model: 'openai/gpt-5.6-sol', contextTokens: 1_050_000 },
378
+ ref: {
379
+ provider: 'openrouter',
380
+ model: 'openai/gpt-5.6-sol',
381
+ contextTokens: 1_050_000,
382
+ acceptsImages: true,
383
+ },
365
384
  keyEnv: 'OPENROUTER_API_KEY',
366
385
  providerLabel: 'OpenRouter',
367
386
  },
368
387
  subscription: {
369
- ref: { provider: 'openai', model: 'gpt-5.6-sol', harness: 'codex', contextTokens: 1_050_000 },
388
+ ref: {
389
+ provider: 'openai',
390
+ model: 'gpt-5.6-sol',
391
+ harness: 'codex',
392
+ contextTokens: 1_050_000,
393
+ acceptsImages: true,
394
+ },
370
395
  vendor: 'codex',
371
396
  },
372
397
  },
@@ -377,7 +402,12 @@ export const MODEL_CATALOG = [
377
402
  description: "OpenAI's balanced everyday model — GPT-5.5-class capability at a fraction of the cost. " +
378
403
  'The migration target for GPT-5.4, which Codex retires on 31 Aug 2026.',
379
404
  openrouter: {
380
- ref: { provider: 'openrouter', model: 'openai/gpt-5.6-terra', contextTokens: 1_050_000 },
405
+ ref: {
406
+ provider: 'openrouter',
407
+ model: 'openai/gpt-5.6-terra',
408
+ contextTokens: 1_050_000,
409
+ acceptsImages: true,
410
+ },
381
411
  keyEnv: 'OPENROUTER_API_KEY',
382
412
  providerLabel: 'OpenRouter',
383
413
  },
@@ -387,6 +417,7 @@ export const MODEL_CATALOG = [
387
417
  model: 'gpt-5.6-terra',
388
418
  harness: 'codex',
389
419
  contextTokens: 1_050_000,
420
+ acceptsImages: true,
390
421
  },
391
422
  vendor: 'codex',
392
423
  },
@@ -398,7 +429,12 @@ export const MODEL_CATALOG = [
398
429
  description: "OpenAI's fastest, cheapest GPT-5.6 tier — for clear, repeatable tasks. The migration " +
399
430
  'target for GPT-5.4 mini.',
400
431
  openrouter: {
401
- ref: { provider: 'openrouter', model: 'openai/gpt-5.6-luna', contextTokens: 1_050_000 },
432
+ ref: {
433
+ provider: 'openrouter',
434
+ model: 'openai/gpt-5.6-luna',
435
+ contextTokens: 1_050_000,
436
+ acceptsImages: true,
437
+ },
402
438
  keyEnv: 'OPENROUTER_API_KEY',
403
439
  providerLabel: 'OpenRouter',
404
440
  },
@@ -408,6 +444,7 @@ export const MODEL_CATALOG = [
408
444
  model: 'gpt-5.6-luna',
409
445
  harness: 'codex',
410
446
  contextTokens: 1_050_000,
447
+ acceptsImages: true,
411
448
  },
412
449
  vendor: 'codex',
413
450
  },
@@ -420,14 +457,25 @@ export const MODEL_CATALOG = [
420
457
  'ChatGPT subscription, pay-as-you-go through OpenRouter (billed at OpenAI rates), or ' +
421
458
  'on AWS Bedrock. The newest OpenAI generation Bedrock serves: the GPT-5.6 tiers are ' +
422
459
  'Codex/OpenRouter only.',
423
- bedrock: { baseModelId: 'openai.gpt-5.5', contextTokens: 1_050_000 },
460
+ bedrock: { baseModelId: 'openai.gpt-5.5', contextTokens: 1_050_000, acceptsImages: true },
424
461
  openrouter: {
425
- ref: { provider: 'openrouter', model: 'openai/gpt-5.5', contextTokens: 1_050_000 },
462
+ ref: {
463
+ provider: 'openrouter',
464
+ model: 'openai/gpt-5.5',
465
+ contextTokens: 1_050_000,
466
+ acceptsImages: true,
467
+ },
426
468
  keyEnv: 'OPENROUTER_API_KEY',
427
469
  providerLabel: 'OpenRouter',
428
470
  },
429
471
  subscription: {
430
- ref: { provider: 'openai', model: 'gpt-5.5', harness: 'codex', contextTokens: 1_050_000 },
472
+ ref: {
473
+ provider: 'openai',
474
+ model: 'gpt-5.5',
475
+ harness: 'codex',
476
+ contextTokens: 1_050_000,
477
+ acceptsImages: true,
478
+ },
431
479
  vendor: 'codex',
432
480
  },
433
481
  },
@@ -455,6 +503,7 @@ export const MODEL_CATALOG = [
455
503
  provider: 'openrouter',
456
504
  model: 'google/gemini-3.1-pro-preview',
457
505
  contextTokens: 1_048_576,
506
+ acceptsImages: true,
458
507
  },
459
508
  keyEnv: 'OPENROUTER_API_KEY',
460
509
  providerLabel: 'OpenRouter',
@@ -467,7 +516,12 @@ export const MODEL_CATALOG = [
467
516
  description: "Google's newest model and its positioned workhorse — 1M-token context at a fraction of " +
468
517
  'Pro pricing. Via OpenRouter, billed at Google rates.',
469
518
  openrouter: {
470
- ref: { provider: 'openrouter', model: 'google/gemini-3.6-flash', contextTokens: 1_048_576 },
519
+ ref: {
520
+ provider: 'openrouter',
521
+ model: 'google/gemini-3.6-flash',
522
+ contextTokens: 1_048_576,
523
+ acceptsImages: true,
524
+ },
471
525
  keyEnv: 'OPENROUTER_API_KEY',
472
526
  providerLabel: 'OpenRouter',
473
527
  },
@@ -667,6 +721,9 @@ const FLAVOR_HANDLERS = {
667
721
  // deployment that hasn't configured Bedrock, which is most of them.
668
722
  model: resolveBedrockModelId(m.bedrock.baseModelId, caps) ?? m.bedrock.baseModelId,
669
723
  ...(m.bedrock.contextTokens ? { contextTokens: m.bedrock.contextTokens } : {}),
724
+ ...(m.bedrock.acceptsImages === undefined
725
+ ? {}
726
+ : { acceptsImages: m.bedrock.acceptsImages }),
670
727
  },
671
728
  flavor: 'bedrock',
672
729
  providerLabel: 'AWS Bedrock',