@instruments/materialgraph 0.30.0 → 0.32.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/client.d.ts +14 -43
- package/client.js +14 -45
- package/errors.d.ts +1 -1
- package/errors.js +1 -0
- package/find-companions-types.d.ts +70 -0
- package/find-companions-types.js +12 -0
- package/http-transport.d.ts +1 -1
- package/index.d.ts +1 -3
- package/index.js +0 -1
- package/material-types.d.ts +2 -1
- package/ndjson.d.ts +1 -1
- package/ndjson.js +1 -1
- package/operations.d.ts +1 -1
- package/operations.js +1 -1
- package/package.json +1 -1
- package/response-schemas.generated.d.ts +1 -1
- package/response-schemas.generated.js +31 -39
- package/search-index-plan-types.d.ts +2 -1
- package/search-result-validation.d.ts +0 -2
- package/search-result-validation.js +1 -17
- package/specifications.d.ts +1 -9
- package/specifications.js +0 -12
- package/types.d.ts +2 -63
- package/validation.d.ts +0 -88
- package/validation.js +2 -154
- package/webmcp.generated.js +7 -8
- package/match-stream-types.d.ts +0 -306
- package/match-stream-types.js +0 -65
- package/match-stream.d.ts +0 -22
- package/match-stream.js +0 -308
- package/match-types.d.ts +0 -138
- package/match-types.js +0 -1
package/webmcp.generated.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const json = [
|
|
2
2
|
"[{\"annotations\":{\"readOnlyHint\":true,\"untrustedContentHint\":true},\"description\":\"The stable, authenticated search endpoint, POST JSON-body form: `text`, a raw `image` (`url` or `base64`, embedded server-side) or a `similarTo` seed (`variantId`, `materialBankId` or a pre-computed image-space `vector`), a `category`, `filters` and a `corpusScope`, and `limit`, `cursor`, `view` and `explain`. Every request runs the one search over the index (ADR 0031): the query's plan is read from the cache or the dictionaries (brands, categories, colours and attributes are read from the words), one query runs on the search index, and the page is hydrated in the order the index gave. No model runs while the caller waits. A word no material carries may be corrected first; the response then carries `correctedQuery: { from, to }` and its `note` says which results it shows. Results are one per product. A caller may also send a `category` (a hard gate that replaces the category the words were read as), attribute `filters` (hard token sets: a term, a term set, an exclusion or a presence check; OR within one attribute, AND across attributes) and a `corpusScope`. Each becomes a field of the query's plan and runs in the same index query; none of them changes the order. A category or filters can define a page without words. `explain.plan.plan` shows the plan with them on it, and `explain.plan.signature` covers them, so one request gives one signature. A look-alike search reads the seed's nearest materials from the image namespace; the index keeps those inside whatever the words filter to and orders them by image similarity. A field the contract does not declare is a 400 naming it, with near misses; weights, mood, colours, text modes and sorts are no longer part of the request, and brands and colours are read from `text`. `?explain=1` on the query string is honoured as a shorthand for body `explain: true`; an explicit body `explain` (true or false) always wins. The `query` echo never carries raw image bytes or a vector, only `{ type }`. Send `Accept: application/x-ndjson` for one `{ type: \\\"response\\\", status, body }` line carrying exactly what the buffered form answers. Search is dynamic, so success responses carry `Cache-Control: no-store`. Requires the `mg:read` bearer scope.\",\"inputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"brands\":{\"description\":\"Brands the page must come from: canonical brand ids, exact slugs (\\\"sherwin-williams\\\") or exact display names (\\\"Sherwin-Williams\\\"). They replace the brands `text` was read as. An empty list is the same request as omitting it — every brand. An unrecognised value is a 400 naming it; a display name shared by more than one brand is a 400 naming the exact slugs to choose between; a brand MaterialGraph holds no materials under is a 400 naming a populated sibling when one exists.\",\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1}},\"category\":{\"type\":\"object\",\"properties\":{\"filter\":{\"minItems\":1,\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Only these public categories are returned: category-group or product-type display names (case-insensitive) or taxonomy keys. A group stands for every product type under it. An unknown value is a 400 listing every valid name.\"}},\"required\":[\"filter\"],\"additionalProperties\":false,\"description\":\"A hard category gate. It replaces the category the words were read as.\"},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"pattern\":\"^#?[0-9a-f]{6}$\",\"description\":\"The colour to order by, e.g. \\\"#9CAF88\\\".\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\"",
|
|
3
3
|
",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"hex\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"variantId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A Variant whose own colour to order by: materials the same colour as this one. A Variant with no colour on the index is a 400.\"}},\"required\":[\"variantId\"],\"additionalProperties\":false}],\"description\":\"Order the page by a colour: `hex`, or `variantId` for the colour of an existing Variant. The page is the colour's family, nearest first by OKLab distance; it replaces any colour read from `text`.\"},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"all\",\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"],\"description\":\"Which corpus to answer from. samplizeCatalogue admits published US paint colours regardless of stock. ABSENT (or 'all') means the WHOLE GRAPH — every material MaterialGraph knows, orderable or not; absence is never a narrower default. Three transaction-oriented scopes gate on governed CHANNEL membership: 'materialBankNaOrderable' (Material Bank North America, ~277,000 materials), 'materialBankEuOrderable' (Material Bank Europe, ~65,000) and 'designShopOrderable' (DesignShop, ~34,000, with the products DesignShop hides from browse excluded). 'materialBankNaAndCatalogue' is the one-query union of Material Bank North America and the governed Catalogue editorial discovery corpus; that union does not by itself claim every member is transactable. 'materialBankOrderable' is NOT one of them: it selects materials carrying a Material Bank identity, which is a provenance signal rather than a channel one, and it admits 98.4% of the graph — use it to exclude crawl-sourced brands, not to mean orderable. A scope answers membership in its named governed corpus, never suitability: scope on channel, then refine on sector. Every scope is applied INSIDE the query: `limit` fills with eligible rows and `counts` describe the scoped corpus, which post-filtering a page cannot give you. An unknown value is a 400 naming it, never a silent fall back to the whole graph.\"},\"cursor\":{\"description\":\"Opaque cursor from a previous response's `cursor`, for the next page of the same query. A cursor from another query is a 409 telling the caller to restart from the first page.\",\"type\":\"string\",\"minLength\":1},\"explain\":{\"description\":\"Add `timings`: wall-clock milliseconds for reading the plan (`planMs`), the index query (`indexMs`) and hydrating the page (`pageMs`), and `explain.plan`: the receipt of the plan the search ran on, with the plan itself.\",\"type\":\"boolean\"},\"filters\":{\"minItems\":1,\"maxItems\":24,\"type\":\"array\",\"items\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"term\":{\"type\":\"string\",\"minLength\":1,\"description\":\"The canonical term the value must carry, e.g. \\\"textile\\\".\"}},\"required\":[\"attributeId\",\"term\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"terms\":{\"minItems\":1,\"maxItems\":50,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Canonical terms, any one of which satisfies the filter.\"}},\"required\":[\"attributeId\",\"terms\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"excludesTerm\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A canonical term the value must not carry. A material ",
|
|
4
|
-
"that states nothing for the attribute passes.\"}},\"required\":[\"attributeId\",\"excludesTerm\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"hasValue\":{\"type\":\"boolean\",\"const\":true,\"description\":\"Require any stated value.\"}},\"required\":[\"attributeId\",\"hasValue\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A number the search index cuts into bands: a numeric attribute such as \\\"nrc_rating\\\" or \\\"lead_time_days\\\", a dimensions lens such as \\\"dimensions.thickness_mm\\\" or \\\"dimensions.short_side_mm\\\" (millimetres), or a composition share such as \\\"composition_weighted.wool\\\" (0 to 1).\"},\"max\":{\"description\":\"Inclusive upper bound. Omit for a floor.\",\"type\":\"number\"},\"min\":{\"description\":\"Inclusive lower bound. Omit for a ceiling.\",\"type\":\"number\"}},\"required\":[\"attributeId\"],\"additionalProperties\":false}]},\"description\":\"Attribute filters, every one hard, run as token sets on the search index. Each entry is a term (`attributeId` + `term`), a term set (`attributeId` + `terms`, any one satisfies it), an exclusion (`attributeId` + `excludesTerm`; a material stating nothing passes), a presence check (`attributeId` + `hasValue: true`) or a numeric range (`attributeId` + `min` and/or `max`, inclusive), read as the number bands wholly inside it, so a bound between two band edges is read inward and a value the index cannot prove in range is left out. Entries on one attribute are OR'd; entries on different attributes AND together. They are added to what the words were read as and change no ordering. An attribute or term the index does not carry is a 400 naming it.\"},\"image\":{\"description\":\"A query image to search by (URL or base64). It is embedded, and the page is its nearest materials in the image namespace; `text`, when also given, narrows them.\",\"oneOf\":[{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"const\":\"url\"},\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"HTTP(S) URL of the query image. MUST be an https URL.\"}},\"required\":[\"type\",\"url\"]},{\"type\":\"object\",\"properties\":{\"data\":{\"type\":\"string\",\"minLength\":1,\"description\":\"Base64-encoded image bytes (or a data URI) the caller already holds — e.g. a form upload — so there is nothing to host.\"},\"type\":{\"type\":\"string\",\"const\":\"base64\"}},\"required\":[\"data\",\"type\"]}],\"type\":\"object\"},\"limit\":{\"description\":\"Products per page (max 60). Absent, the search's own page size.\",\"type\":\"integer\",\"minimum\":1,\"maximum\":60},\"returnAttributes\":{\"maxItems\":8,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Attribute ids whose RESOLVED VALUE should ride each result, under `attributes` keyed by attribute id. Values resolve with the normal variant-over-product precedence. THREE STATES, and they are different: an attribute you did not ask for is not a key at all; an attribute you asked for that this variant carries no accepted value for is `null`; anything else is the value (a string, or an array for a multi-valued attribute). An unknown attribute id is refused naming it, never silently dropped. Pair it with `filters` to show what you filtered on.\"},\"similarTo\":{\"description\":\"Find materials that LOOK like a seed: `variantId` seeds from an existing Variant's image, `materialBankId` from a Material Bank SKU (an unknown SKU is a 400 naming it), `vector` from a pre-computed image-space halfvec literal (`[a,b,...]`). `text`, when also given, narrows the look-alikes.\",\"anyOf\":[{\"type\":\"object\",\"properties\":{\"variantId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"variantId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"materialBankId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"materialBankId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"vector\":{\"type\":\"string\",\"minLength\":1}},\"
|
|
5
|
-
"\":{\"description\":\"Free-text query (\\\"oak flooring\\\", \\\"sage green velvet\\\", \\\"Kvadrat wool\\\"). Brands, categories, colours and attributes are read from the words unless `brands`, `category`, `colour` or `filters` says so instead; a word no material carries may be corrected, and the response says so under `correctedQuery`. May be omitted when `brands`, `category` or `filters` says what to find.\",\"type\":\"string\",\"maxLength\":500},\"view\":{\"default\":\"full\",\"description\":\"Result projection. \\\"full\\\" (default) returns the complete result items; \\\"card\\\" the lean grid projection. The response echoes `view`, which discriminates the `results` union.\",\"type\":\"string\",\"enum\":[\"full\",\"card\"]}},\"additionalProperties\":false}}},\"method\":\"POST\",\"name\":\"search\",\"operationId\":\"search_materials_post\",\"outputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"data\":{\"oneOf\":[{\"type\":\"object\",\"properties\":{\"results\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"resultId\":{\"type\":\"string\",\"description\":\"This exact hit's attribution key — `<responseId>:<rank>`, where rank is 1-based within THIS response. Unique across pages, because each page is its own response with its own id. Store it verbatim next to the outcome; it is opaque, and `attribution.responseId` is the field to group by.\"},\"variantId\":{\"type\":\"string\"},\"brand\":{\"type\":\"string\"},\"product\":{\"type\":\"string\"},\"brandSlug\":{\"type\":[\"string\",\"null\"]},\"productId\":{\"type\":[\"string\",\"null\"]},\"materialBankId\":{\"description\":\"The variant's Material Bank SKU — the ONE EXTERNAL identifier on a result, in contrast to the OPAQUE `variantId`: it is the id you are expected to match against Material Bank's own catalogue (carts, ordering and analytics all key on it), so a result list can be joined without a second lookup. Populated by the search and by Match alike. ABSENT means no MB identity is known for the variant, never that the SKU cannot be ordered; presence is the orderability tell, absence is silence.\",\"type\":\"string\"},\"manufacturerCode\":{\"description\":\"The governed manufacturer/source-native item code from `variants.code` (for example \\\"GADLC02\\\"). Populated when the full-result retrieval source carries that canonical field; Match always hydrates it from the variant row. ABSENT means unknown or an older external serving projection, never an invented code. Independent of materialBankId.\",\"type\":\"string\"},\"projectSaveCapability\":{\"description\":\"Explicit source-governed permission to save this exact source-coded variant to a Project. ABSENT means unknown/not allowed; it is never inferred from the brand or name.\",\"type\":\"string\",\"const\":\"allowed\"},\"sampleable\":{\"description\":\"Whether a physical sample is explicitly known to be orderable. Absent means unknown, never unavailable.\",\"type\":\"boolean\"},\"sourceStatus\":{\"description\":\"The governed data status supporting Project capture. ABSENT means unknown. Provisional data remains source-backed but is not a verified catalogue claim.\",\"type\":\"string\",\"const\":\"provisional\"},\"productType\":{\"type\":\"string\"},\"color\":{\"type\":[\"string\",\"null\"]},\"variantName\":{\"type\":[\"string\",\"null\"]},\"imageUrl\":{\"type\":[\"string\",\"null\"]},\"imageSha256\":{\"description\":\"SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Lets a caller key a cache or dedupe on the asset rather than its URL. ABSENT means no hash is on record, never that there is no image.\",\"type\":\"string\"},\"hasImage\":{\"type\":\"boolean\"},\"variantCount\":{\"description\":\"How many eligible variants the row's product has, the same set `list_variants` pages, so a follow-up list of the product returns this many: the card's \\\"12 colourways\\\". ABSENT means the product is unknown or has no eligible variant.\",\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":9007199254740991},\"palette\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` of the swatch, as extracted from the product image.\"},\"name\":{\"description\":\"Stored human colour name for the swatch, when
|
|
6
|
-
"\"type\":\"number\",\"description\":\"The swatch's share of the analysed image, in [0,1].\"}},\"required\":[\"hex\",\"proportion\"],\"additionalProperties\":false},\"description\":\"The material's main-image palette — the FULL stored palette, uncapped and in stored order. Colours are EXTRACTED FROM PRODUCT IMAGERY (visual likeness, never a declared colour specification). A one-swatch palette means the extractor found one colour — solid-colour materials are genuinely monochrome — never that the list was trimmed. This array is always present: EMPTY means nothing is on record (unknown), not 'this material has no colours'.\"},\"colourMeta\":{\"type\":\"object\",\"properties\":{\"dominantFamily\":{\"type\":\"string\"},\"dominantHex\":{\"type\":\"string\"},\"mood\":{\"type\":\"string\"}},\"additionalProperties\":false},\"colourChip\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` to fill the chip with. EXTRACTED FROM the product image (a visual likeness), never a manufacturer-declared colour specification — surfaces must not present it as one.\"}},\"required\":[\"hex\"],\"additionalProperties\":false,\"description\":\"Present when this material's product imagery carries nothing beyond one colour, so a surface should render that colour rather than the photograph. Set for COATINGS (paints, primers, stains, floor coatings) whose stored palette quantises to a single swatch — a paint's photo is a flat fill, and the colour we hold structured beats a JPEG of it. ABSENT means the question was not established (unknown product type, unextracted or multi-swatch palette) and the image should be rendered; it NEVER asserts 'this is not a coating'.\"},\"attributes\":{\"description\":\"Resolved attribute values for the ids sent in `returnAttributes`, keyed by attribute id. ABSENT entirely when `returnAttributes` was not sent. A key present with `null` means this variant carries no accepted value for that attribute — absent is not empty and neither is null: the three states are distinct on purpose. Values resolve with the normal variant-over-product precedence.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}},{\"type\":\"null\"}]}},\"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"uired\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category, brands, wanted and excluded attribute terms (each hard or soft, with its fill), the colour, the words left for text, and the caller's corpus scope when one was sent.\"},\"signature\":{\"type\":\"string\"},\"source\":{\"type\":\"string\",\"enum\":[\"dictionary\",\"jev\"]},\"version\":{\"type\":\"string\"}},\"required\":[\"cached\",\"plan\",\"signature\",\"source\",\"version\"],\"additionalProperties\":false}},\"required\":[\"plan\"],\"additionalProperties\":false},\"query\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}},\"seed\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}}},\"required\":[\"results\",\"view\",\"suggestions\",\"mode\",\"maxScore\",\"query\"],\"additionalProperties\":false}],\"type\":\"object\"},\"links\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false},\"meta\":{\"type\":\"object\",\"properties\":{\"operationId\":{\"type\":\"string\",\"enum\":[\"search_materials_post\",\"search_materials_get\"]},\"requestId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"operationId\",\"requestId\"],\"additionalProperties\":false},\"warnings\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1}}},\"required\":[\"data\",\"links\",\"meta\",\"warnings\"],\"additionalProperties\":false}}},\"path\":\"/api/v1/search\",\"requiredHeaders\":[],\"requiresVisibleConfirmation\":false}]",
|
|
4
|
+
"that states nothing for the attribute passes.\"}},\"required\":[\"attributeId\",\"excludesTerm\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"An attribute the search index carries, e.g. \\\"primary_material\\\" or \\\"colour_mood\\\", or \\\"certification_programme\\\" for any certification programme.\"},\"hasValue\":{\"type\":\"boolean\",\"const\":true,\"description\":\"Require any stated value.\"}},\"required\":[\"attributeId\",\"hasValue\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\",\"minLength\":1,\"description\":\"A number the search index cuts into bands: a numeric attribute such as \\\"nrc_rating\\\" or \\\"lead_time_days\\\", a dimensions lens such as \\\"dimensions.thickness_mm\\\" or \\\"dimensions.short_side_mm\\\" (millimetres), or a composition share such as \\\"composition_weighted.wool\\\" (0 to 1).\"},\"max\":{\"description\":\"Inclusive upper bound. Omit for a floor.\",\"type\":\"number\"},\"min\":{\"description\":\"Inclusive lower bound. Omit for a ceiling.\",\"type\":\"number\"}},\"required\":[\"attributeId\"],\"additionalProperties\":false}]},\"description\":\"Attribute filters, every one hard, run as token sets on the search index. Each entry is a term (`attributeId` + `term`), a term set (`attributeId` + `terms`, any one satisfies it), an exclusion (`attributeId` + `excludesTerm`; a material stating nothing passes), a presence check (`attributeId` + `hasValue: true`) or a numeric range (`attributeId` + `min` and/or `max`, inclusive), read as the number bands wholly inside it, so a bound between two band edges is read inward and a value the index cannot prove in range is left out. Entries on one attribute are OR'd; entries on different attributes AND together. They are added to what the words were read as and change no ordering. An attribute or term the index does not carry is a 400 naming it.\"},\"image\":{\"description\":\"A query image to search by (URL or base64). It is embedded, and the page is its nearest materials in the image namespace; `text`, when also given, narrows them.\",\"oneOf\":[{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"const\":\"url\"},\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"HTTP(S) URL of the query image. MUST be an https URL.\"}},\"required\":[\"type\",\"url\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"data\":{\"type\":\"string\",\"minLength\":1,\"description\":\"Base64-encoded image bytes (or a data URI) the caller already holds — e.g. a form upload — so there is nothing to host.\"},\"type\":{\"type\":\"string\",\"const\":\"base64\"}},\"required\":[\"data\",\"type\"],\"additionalProperties\":false}],\"type\":\"object\"},\"limit\":{\"description\":\"Products per page (max 60). Absent, the search's own page size.\",\"type\":\"integer\",\"minimum\":1,\"maximum\":60},\"returnAttributes\":{\"maxItems\":8,\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1},\"description\":\"Attribute ids whose RESOLVED VALUE should ride each result, under `attributes` keyed by attribute id. Values resolve with the normal variant-over-product precedence. THREE STATES, and they are different: an attribute you did not ask for is not a key at all; an attribute you asked for that this variant carries no accepted value for is `null`; anything else is the value (a string, or an array for a multi-valued attribute). An unknown attribute id is refused naming it, never silently dropped. Pair it with `filters` to show what you filtered on.\"},\"similarTo\":{\"description\":\"Find materials that LOOK like a seed: `variantId` seeds from an existing Variant's image, `materialBankId` from a Material Bank SKU (an unknown SKU is a 400 naming it), `vector` from a pre-computed image-space halfvec literal (`[a,b,...]`). `text`, when also given, narrows the look-alikes.\",\"anyOf\":[{\"type\":\"object\",\"properties\":{\"variantId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"variantId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"materialBankId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"materialBankId\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"vector\":{\"type\":\"string\",\"minLength\":1}},\"",
|
|
5
|
+
"required\":[\"vector\"],\"additionalProperties\":false}]},\"text\":{\"description\":\"Free-text query (\\\"oak flooring\\\", \\\"sage green velvet\\\", \\\"Kvadrat wool\\\"). Brands, categories, colours and attributes are read from the words unless `brands`, `category`, `colour` or `filters` says so instead; a word no material carries may be corrected, and the response says so under `correctedQuery`. May be omitted when `brands`, `category` or `filters` says what to find.\",\"type\":\"string\",\"maxLength\":500},\"view\":{\"default\":\"full\",\"description\":\"Result projection. \\\"full\\\" (default) returns the complete result items; \\\"card\\\" the lean grid projection. The response echoes `view`, which discriminates the `results` union.\",\"type\":\"string\",\"enum\":[\"full\",\"card\"]}},\"additionalProperties\":false}}},\"method\":\"POST\",\"name\":\"search\",\"operationId\":\"search_materials_post\",\"outputSchema\":{\"$ref\":\"#/$defs/schema0\",\"$defs\":{\"schema0\":{\"type\":\"object\",\"properties\":{\"data\":{\"oneOf\":[{\"type\":\"object\",\"properties\":{\"results\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"resultId\":{\"type\":\"string\",\"description\":\"This exact hit's attribution key — `<responseId>:<rank>`, where rank is 1-based within THIS response. Unique across pages, because each page is its own response with its own id. Store it verbatim next to the outcome; it is opaque, and `attribution.responseId` is the field to group by.\"},\"variantId\":{\"type\":\"string\"},\"brand\":{\"type\":\"string\"},\"product\":{\"type\":\"string\"},\"brandSlug\":{\"type\":[\"string\",\"null\"]},\"productId\":{\"type\":[\"string\",\"null\"]},\"materialBankId\":{\"description\":\"The variant's Material Bank SKU — the ONE EXTERNAL identifier on a result, in contrast to the OPAQUE `variantId`: it is the id you are expected to match against Material Bank's own catalogue (carts, ordering and analytics all key on it), so a result list can be joined without a second lookup. Populated by the search and by Match alike. ABSENT means no MB identity is known for the variant, never that the SKU cannot be ordered; presence is the orderability tell, absence is silence.\",\"type\":\"string\"},\"manufacturerCode\":{\"description\":\"The governed manufacturer/source-native item code from `variants.code` (for example \\\"GADLC02\\\"). Populated when the full-result retrieval source carries that canonical field; Match always hydrates it from the variant row. ABSENT means unknown or an older external serving projection, never an invented code. Independent of materialBankId.\",\"type\":\"string\"},\"projectSaveCapability\":{\"description\":\"Explicit source-governed permission to save this exact source-coded variant to a Project. ABSENT means unknown/not allowed; it is never inferred from the brand or name.\",\"type\":\"string\",\"const\":\"allowed\"},\"sampleable\":{\"description\":\"Whether a physical sample is explicitly known to be orderable. Absent means unknown, never unavailable.\",\"type\":\"boolean\"},\"sourceStatus\":{\"description\":\"The governed data status supporting Project capture. ABSENT means unknown. Provisional data remains source-backed but is not a verified catalogue claim.\",\"type\":\"string\",\"const\":\"provisional\"},\"productType\":{\"type\":\"string\"},\"color\":{\"type\":[\"string\",\"null\"]},\"variantName\":{\"type\":[\"string\",\"null\"]},\"imageUrl\":{\"type\":[\"string\",\"null\"]},\"imageSha256\":{\"description\":\"SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Lets a caller key a cache or dedupe on the asset rather than its URL. ABSENT means no hash is on record, never that there is no image.\",\"type\":\"string\"},\"hasImage\":{\"type\":\"boolean\"},\"variantCount\":{\"description\":\"How many eligible variants the row's product has, the same set `list_variants` pages, so a follow-up list of the product returns this many: the card's \\\"12 colourways\\\". ABSENT means the product is unknown or has no eligible variant.\",\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":9007199254740991},\"palette\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` of the swatch, as extracted from the product image.\"},\"name\":{\"description\":\"Stored human colour name for the swatch, when on",
|
|
6
|
+
"e was extracted.\",\"type\":[\"string\",\"null\"]},\"proportion\":{\"type\":\"number\",\"description\":\"The swatch's share of the analysed image, in [0,1].\"}},\"required\":[\"hex\",\"proportion\"],\"additionalProperties\":false},\"description\":\"The material's main-image palette — the FULL stored palette, uncapped and in stored order. Colours are EXTRACTED FROM PRODUCT IMAGERY (visual likeness, never a declared colour specification). A one-swatch palette means the extractor found one colour — solid-colour materials are genuinely monochrome — never that the list was trimmed. This array is always present: EMPTY means nothing is on record (unknown), not 'this material has no colours'.\"},\"colourMeta\":{\"type\":\"object\",\"properties\":{\"dominantFamily\":{\"type\":\"string\"},\"dominantHex\":{\"type\":\"string\"},\"mood\":{\"type\":\"string\"}},\"additionalProperties\":false},\"colourChip\":{\"type\":\"object\",\"properties\":{\"hex\":{\"type\":\"string\",\"description\":\"`#rrggbb` to fill the chip with. EXTRACTED FROM the product image (a visual likeness), never a manufacturer-declared colour specification — surfaces must not present it as one.\"}},\"required\":[\"hex\"],\"additionalProperties\":false,\"description\":\"Present when this material's product imagery carries nothing beyond one colour, so a surface should render that colour rather than the photograph. Set for COATINGS (paints, primers, stains, floor coatings) whose stored palette quantises to a single swatch — a paint's photo is a flat fill, and the colour we hold structured beats a JPEG of it. ABSENT means the question was not established (unknown product type, unextracted or multi-swatch palette) and the image should be rendered; it NEVER asserts 'this is not a coating'.\"},\"attributes\":{\"description\":\"Resolved attribute values for the ids sent in `returnAttributes`, keyed by attribute id. ABSENT entirely when `returnAttributes` was not sent. A key present with `null` means this variant carries no accepted value for that attribute — absent is not empty and neither is null: the three states are distinct on purpose. Values resolve with the normal variant-over-product precedence.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}},{\"type\":\"null\"}]}},\"score\":{\"type\":\"number\",\"description\":\"The selected mode's weighted primary score on the [0, maxScore] scale.\"},\"retired\":{\"description\":\"MB lists the SKU as not visible/retired; demoted in ranking. Omitted when false.\",\"type\":\"boolean\"}},\"required\":[\"variantId\",\"brand\",\"product\",\"brandSlug\",\"productId\",\"color\",\"variantName\",\"imageUrl\",\"hasImage\",\"palette\",\"score\"],\"additionalProperties\":false}},\"view\":{\"default\":\"full\",\"description\":\"Projection echo — always 'full' on this envelope variant.\",\"type\":\"string\",\"const\":\"full\"},\"correctedQuery\":{\"description\":\"Present when a word no material carries was corrected before the search ran: `from` is the query as typed (normalised), `to` the phrasing the page shows results for.\",\"type\":\"object\",\"properties\":{\"from\":{\"type\":\"string\"},\"to\":{\"type\":\"string\"}},\"required\":[\"from\",\"to\"],\"additionalProperties\":false},\"attribution\":{\"type\":\"object\",\"properties\":{\"basis\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\",\"match\"],\"description\":\"The ranking basis. On /api/v1/search this equals the envelope's `mode`. The historical match basis remains readable for stored outcomes.\"},\"issuedAt\":{\"type\":\"string\",\"description\":\"ISO-8601 timestamp of when this response was assembled, so a stored outcome carries its own age without a second lookup.\"},\"responseId\":{\"type\":\"string\",\"description\":\"This response's stable id — the same value as the `X-Request-Id` header. Store it next to the outcome (an order, a save, a click) to join that outcome back to the ranking that produced it. Opaque: round-trip it verbatim, never parse it.\"}},\"required\":[\"basis\",\"issuedAt\",\"responseId\"],\"additionalProperties\":false,\"description\":\"Result attribution receipt. Present on every successful ranked response. Nothing on our side retains it — what you store IS the record.\"},\"s",
|
|
7
|
+
"uggestions\":{\"default\":[],\"description\":\"Always empty: the one search offers no refinements. Read nothing from it.\",\"maxItems\":0,\"type\":\"array\",\"items\":{\"not\":{}}},\"mode\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\"],\"description\":\"What ordered the page: 'image' (a look-alike: image similarity to the seed), 'colour' (the words or the caller named a colour: colour distance inside that colour's family), 'lexical' (the query's words, ranked by text rank on the index), 'attribute' (no words left to rank on: the category and filters define the page), or 'agent' (the search agent chose these variants and their order; scores are rank-based, 1 for the first result falling linearly, and `maxScore` is 1).\"},\"maxScore\":{\"type\":\"number\"},\"note\":{\"type\":\"string\"},\"cursor\":{\"type\":\"string\"},\"timings\":{\"description\":\"Wall-clock milliseconds per step of the search, keyed by step id. The key set is open and depends on the path a query took, so read it by iterating rather than by naming a key. Present only when `explain` is set: diagnostic, not part of the ranking contract.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"type\":\"number\"}},\"explain\":{\"description\":\"Present only under `explain`: the receipt of the plan the search ran on. Diagnostic, like `timings`.\",\"type\":\"object\",\"properties\":{\"plan\":{\"type\":\"object\",\"properties\":{\"cached\":{\"type\":\"boolean\"},\"plan\":{\"type\":\"object\",\"properties\":{\"brands\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"names\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"phrase\":{\"type\":\"string\"}},\"required\":[\"ids\",\"names\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"category\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"label\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"productTypeIds\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"label\",\"phrase\",\"productTypeIds\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"family12\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"familyId\":{\"type\":\"string\"},\"hex\":{\"type\":\"string\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"phrase\":{\"type\":\"string\"},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"family12\",\"familyId\",\"hex\",\"oklab\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"]},\"excludeBrands\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"excludes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"term\":{\"type\":\"string\"}},\"required\":[\"attributeId\",\"phrase\",\"term\"],\"additionalProperties\":false}},\"leftover\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"normalised\":{\"type\":\"string\"},\"softAlone\":{\"type\":\"boolean\"},\"vendorColourNames\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"wants\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"fill\":{\"type\":\"number\"},\"phrase\":{\"type\":\"string\"},\"presence\":{\"type\":\"boolean\",\"const\":true},\"strength\":{\"type\":\"string\",\"enum\":[\"hard\",\"soft\"]},\"terms\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"attributeId\",\"fill\",\"phrase\",\"strength\",\"terms\"],\"additionalProperties\":false}}},\"required\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false",
|
|
8
|
+
",\"description\":\"The plan the search ran on: the category, brands, wanted and excluded attribute terms (each hard or soft, with its fill), the colour, the words left for text, and the caller's corpus scope when one was sent.\"},\"signature\":{\"type\":\"string\"},\"source\":{\"type\":\"string\",\"enum\":[\"dictionary\",\"jev\"]},\"version\":{\"type\":\"string\"}},\"required\":[\"cached\",\"plan\",\"signature\",\"source\",\"version\"],\"additionalProperties\":false}},\"required\":[\"plan\"],\"additionalProperties\":false},\"query\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}},\"seed\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}}},\"required\":[\"results\",\"view\",\"suggestions\",\"mode\",\"maxScore\",\"query\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"results\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributes\":{\"description\":\"Resolved attribute values for the ids sent in `returnAttributes`, keyed by attribute id. ABSENT entirely when `returnAttributes` was not sent. A key present with `null` means this variant carries no accepted value for that attribute — absent is not empty and neither is null: the three states are distinct on purpose. Values resolve with the normal variant-over-product precedence.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"anyOf\":[{\"type\":\"string\"},{\"type\":\"array\",\"items\":{\"type\":\"string\"}},{\"type\":\"null\"}]}},\"brand\":{\"type\":\"string\"},\"brandSlug\":{\"type\":[\"string\",\"null\"]},\"imageSha256\":{\"description\":\"SHA-256 of the displayed image `imageUrl` points at, as a hex digest. Lets a caller key a cache or dedupe on the asset rather than its URL. ABSENT means no hash is on record, never that there is no image.\",\"type\":\"string\"},\"imageUrl\":{\"type\":[\"string\",\"null\"]},\"manufacturerCode\":{\"description\":\"The governed manufacturer/source-native item code from `variants.code` (for example \\\"K-7265-BV\\\") — the same key and the same value the full item publishes. It is what separates two cards a reader cannot otherwise tell apart: brand, product name and variant name are shared by 280,334 of 371,515 cardable variants, because `name` is the PRODUCT name and a paint product is a whole collection. ABSENT means no code is recorded for the variant, never an invented one.\",\"type\":\"string\"},\"name\":{\"type\":\"string\",\"description\":\"Product name (the full item's `product`).\"},\"productId\":{\"type\":[\"string\",\"null\"]},\"projectSaveCapability\":{\"type\":\"string\",\"const\":\"allowed\"},\"resultId\":{\"type\":\"string\",\"description\":\"This exact hit's attribution key — `<responseId>:<rank>`, where rank is 1-based within THIS response. Unique across pages, because each page is its own response with its own id. Store it verbatim next to the outcome; it is opaque, and `attribution.responseId` is the field to group by.\"},\"sampleable\":{\"description\":\"Whether a physical sample is explicitly known to be orderable. Absent means unknown, never unavailable.\",\"type\":\"boolean\"},\"score\":{\"type\":\"number\"},\"sourceStatus\":{\"type\":\"string\",\"const\":\"provisional\"},\"variantCount\":{\"description\":\"How many eligible variants the row's product has, the same set `list_variants` pages, so a follow-up list of the product returns this many: the card's \\\"12 colourways\\\". ABSENT means the product is unknown or has no eligible variant.\",\"type\":\"integer\",\"exclusiveMinimum\":0,\"maximum\":9007199254740991},\"variantId\":{\"type\":\"string\"},\"variantName\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"brand\",\"brandSlug\",\"imageUrl\",\"name\",\"productId\",\"score\",\"variantId\",\"variantName\"],\"additionalProperties\":false}},\"view\":{\"type\":\"string\",\"const\":\"card\",\"description\":\"Projection echo — always 'card' on this envelope variant.\"},\"correctedQuery\":{\"description\":\"Present when a word no material carries was corrected before the search ran: `from` is the query as typed (normalised), `to` the phrasing the page shows results for.\",\"type\":\"object\",\"properties\":{\"from\":{\"type\":\"string\"},\"to\":{\"type\":\"string\"}},\"required\":[\"from\",\"to\"],\"additionalProperties\":false},\"attribution\":{\"type\":\"object\",\"properties\":{\"basis\":{\"type\":\"string\",",
|
|
9
|
+
"\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\",\"match\"],\"description\":\"The ranking basis. On /api/v1/search this equals the envelope's `mode`. The historical match basis remains readable for stored outcomes.\"},\"issuedAt\":{\"type\":\"string\",\"description\":\"ISO-8601 timestamp of when this response was assembled, so a stored outcome carries its own age without a second lookup.\"},\"responseId\":{\"type\":\"string\",\"description\":\"This response's stable id — the same value as the `X-Request-Id` header. Store it next to the outcome (an order, a save, a click) to join that outcome back to the ranking that produced it. Opaque: round-trip it verbatim, never parse it.\"}},\"required\":[\"basis\",\"issuedAt\",\"responseId\"],\"additionalProperties\":false,\"description\":\"Result attribution receipt. Present on every successful ranked response. Nothing on our side retains it — what you store IS the record.\"},\"suggestions\":{\"default\":[],\"description\":\"Always empty: the one search offers no refinements. Read nothing from it.\",\"maxItems\":0,\"type\":\"array\",\"items\":{\"not\":{}}},\"mode\":{\"type\":\"string\",\"enum\":[\"image\",\"colour\",\"lexical\",\"agent\",\"attribute\"],\"description\":\"What ordered the page: 'image' (a look-alike: image similarity to the seed), 'colour' (the words or the caller named a colour: colour distance inside that colour's family), 'lexical' (the query's words, ranked by text rank on the index), 'attribute' (no words left to rank on: the category and filters define the page), or 'agent' (the search agent chose these variants and their order; scores are rank-based, 1 for the first result falling linearly, and `maxScore` is 1).\"},\"maxScore\":{\"type\":\"number\"},\"note\":{\"type\":\"string\"},\"cursor\":{\"type\":\"string\"},\"timings\":{\"description\":\"Wall-clock milliseconds per step of the search, keyed by step id. The key set is open and depends on the path a query took, so read it by iterating rather than by naming a key. Present only when `explain` is set: diagnostic, not part of the ranking contract.\",\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{\"type\":\"number\"}},\"explain\":{\"description\":\"Present only under `explain`: the receipt of the plan the search ran on. Diagnostic, like `timings`.\",\"type\":\"object\",\"properties\":{\"plan\":{\"type\":\"object\",\"properties\":{\"cached\":{\"type\":\"boolean\"},\"plan\":{\"type\":\"object\",\"properties\":{\"brands\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"names\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"phrase\":{\"type\":\"string\"}},\"required\":[\"ids\",\"names\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"category\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"label\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"productTypeIds\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"label\",\"phrase\",\"productTypeIds\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"colour\":{\"anyOf\":[{\"type\":\"object\",\"properties\":{\"family12\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"familyId\":{\"type\":\"string\"},\"hex\":{\"type\":\"string\"},\"oklab\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":3,\"maxItems\":3},\"phrase\":{\"type\":\"string\"},\"range\":{\"type\":\"object\",\"properties\":{\"chroma\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},\"hue\":{\"anyOf\":[{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2},{\"type\":\"null\"}]},\"lightness\":{\"type\":\"array\",\"prefixItems\":[{\"type\":\"number\"},{\"type\":\"number\"}],\"items\":false,\"minItems\":2,\"maxItems\":2}},\"required\":[\"chroma\",\"hue\",\"lightness\"],\"additionalProperties\":false}},\"required\":[\"family12\",\"familyId\",\"hex\",\"oklab\",\"phrase\"],\"additionalProperties\":false},{\"type\":\"null\"}]},\"corpusScope\":{\"type\":\"string\",\"enum\":[\"samplizeCatalogue\",\"materialBankOrderable\",\"materialBankNaOrderable\",\"materialBankNaAndCatalogue\",\"materialBankEuOrderable\",\"designShopOrderable\"]},\"excludeBrands\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"excludes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"pr",
|
|
10
|
+
"operties\":{\"attributeId\":{\"type\":\"string\"},\"phrase\":{\"type\":\"string\"},\"term\":{\"type\":\"string\"}},\"required\":[\"attributeId\",\"phrase\",\"term\"],\"additionalProperties\":false}},\"leftover\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"normalised\":{\"type\":\"string\"},\"softAlone\":{\"type\":\"boolean\"},\"vendorColourNames\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"wants\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"attributeId\":{\"type\":\"string\"},\"fill\":{\"type\":\"number\"},\"phrase\":{\"type\":\"string\"},\"presence\":{\"type\":\"boolean\",\"const\":true},\"strength\":{\"type\":\"string\",\"enum\":[\"hard\",\"soft\"]},\"terms\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}},\"required\":[\"attributeId\",\"fill\",\"phrase\",\"strength\",\"terms\"],\"additionalProperties\":false}}},\"required\":[\"brands\",\"category\",\"colour\",\"excludeBrands\",\"excludes\",\"leftover\",\"normalised\",\"softAlone\",\"vendorColourNames\",\"wants\"],\"additionalProperties\":false,\"description\":\"The plan the search ran on: the category, brands, wanted and excluded attribute terms (each hard or soft, with its fill), the colour, the words left for text, and the caller's corpus scope when one was sent.\"},\"signature\":{\"type\":\"string\"},\"source\":{\"type\":\"string\",\"enum\":[\"dictionary\",\"jev\"]},\"version\":{\"type\":\"string\"}},\"required\":[\"cached\",\"plan\",\"signature\",\"source\",\"version\"],\"additionalProperties\":false}},\"required\":[\"plan\"],\"additionalProperties\":false},\"query\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}},\"seed\":{\"type\":\"object\",\"propertyNames\":{\"type\":\"string\"},\"additionalProperties\":{}}},\"required\":[\"results\",\"view\",\"suggestions\",\"mode\",\"maxScore\",\"query\"],\"additionalProperties\":false}],\"type\":\"object\"},\"links\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false},\"meta\":{\"type\":\"object\",\"properties\":{\"operationId\":{\"type\":\"string\",\"enum\":[\"search_materials_post\",\"search_materials_get\"]},\"requestId\":{\"type\":\"string\",\"minLength\":1}},\"required\":[\"operationId\",\"requestId\"],\"additionalProperties\":false},\"warnings\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"minLength\":1}}},\"required\":[\"data\",\"links\",\"meta\",\"warnings\"],\"additionalProperties\":false}}},\"path\":\"/api/v1/search\",\"requiredHeaders\":[],\"requiresVisibleConfirmation\":false}]",
|
|
12
11
|
].join("");
|
|
13
12
|
export const WEBMCP_TOOLS = JSON.parse(json);
|
package/match-stream-types.d.ts
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import type { ResponseAttribution } from "./attribution-types.js";
|
|
2
|
-
import type { MatchCategoryInference, MatchColourReading } from "./match-types.js";
|
|
3
|
-
/**
|
|
4
|
-
* The Material Match PROGRESS-STREAM contracts — the wire vocabulary of
|
|
5
|
-
* {@link MaterialGraphClient.matchStream} (`POST /api/v1/search/match` under
|
|
6
|
-
* `Accept: application/x-ndjson`). One JSON object per line; the run ends on a
|
|
7
|
-
* `complete` or an `error` event.
|
|
8
|
-
*
|
|
9
|
-
* These shapes are HAND-MIRRORED from `matchStreamEventSchema` in
|
|
10
|
-
* `@materialgraph/products` — the SDK publishes with zero runtime dependencies,
|
|
11
|
-
* so it cannot import the Zod schema itself. `contract-parity.test.ts` re-checks
|
|
12
|
-
* the mirror against the real schema, deriving the enum members FROM the
|
|
13
|
-
* canonical schemas so a server-side addition fails that test rather than
|
|
14
|
-
* silently widening the client.
|
|
15
|
-
*
|
|
16
|
-
* Every enum here is CLOSED, exactly as the canonical `z.enum(…)` members are.
|
|
17
|
-
* The value lists are exported so a consumer can build an exhaustive switch or a
|
|
18
|
-
* UI legend from the same source the validator uses.
|
|
19
|
-
*/
|
|
20
|
-
import type { SearchResultItem } from "./types.js";
|
|
21
|
-
/** How the workflow classified the uploaded image. */
|
|
22
|
-
export declare const MATCH_IMAGE_TYPES: readonly ["swatch", "installation", "flatplan"];
|
|
23
|
-
export type MatchImageType = (typeof MATCH_IMAGE_TYPES)[number];
|
|
24
|
-
/** Why a Match run ended on an `error` frame (MG-730). */
|
|
25
|
-
export declare const MATCH_ERROR_REASONS: readonly ["upstream_unavailable", "failed"];
|
|
26
|
-
export type MatchErrorReason = (typeof MATCH_ERROR_REASONS)[number];
|
|
27
|
-
/** What a detected surface is FOR — the element the material would serve. */
|
|
28
|
-
export declare const MATCH_MATERIAL_FUNCTIONS: readonly ["flooring", "wall_surface", "ceiling", "partition", "upholstery", "millwork", "countertop", "accent", "sample"];
|
|
29
|
-
export type MatchMaterialFunction = (typeof MATCH_MATERIAL_FUNCTIONS)[number];
|
|
30
|
-
/** The workflow's coarse progress phase, narrated by a `step` event. */
|
|
31
|
-
export declare const MATCH_WORKFLOW_STEPS: readonly ["classifying", "decomposing", "matching", "complete"];
|
|
32
|
-
export type MatchWorkflowStep = (typeof MATCH_WORKFLOW_STEPS)[number];
|
|
33
|
-
/**
|
|
34
|
-
* Where one surface stands in the run.
|
|
35
|
-
*
|
|
36
|
-
* `colour_fallback` (appended, additive): the surface completed, but through
|
|
37
|
-
* the colour lane — its visible sample was too small to read texture, so the
|
|
38
|
-
* results match the region's palette, scoped to the detected category. Such a
|
|
39
|
-
* surface carries a `note` saying so and no `senseCheck` verdicts (there is no
|
|
40
|
-
* texture to verify).
|
|
41
|
-
*/
|
|
42
|
-
export declare const MATCH_SURFACE_STATUSES: readonly ["pending", "matching", "complete", "error", "colour_fallback"];
|
|
43
|
-
export type MatchSurfaceStatus = (typeof MATCH_SURFACE_STATUSES)[number];
|
|
44
|
-
/** Every frame type the stream can carry — the union's discriminant values. */
|
|
45
|
-
export declare const MATCH_STREAM_EVENT_TYPES: readonly ["step", "classified", "surfaces", "surface", "heartbeat", "complete", "error"];
|
|
46
|
-
export type MatchStreamEventType = (typeof MATCH_STREAM_EVENT_TYPES)[number];
|
|
47
|
-
/** Where a surface sits in the image, in Gemini-style 0–1000 image space. */
|
|
48
|
-
export type MatchBoundingBox = {
|
|
49
|
-
x0: number;
|
|
50
|
-
y0: number;
|
|
51
|
-
x1: number;
|
|
52
|
-
y1: number;
|
|
53
|
-
};
|
|
54
|
-
/** One surface the decompose step found in the image. */
|
|
55
|
-
export type MatchDetectedSurface = {
|
|
56
|
-
id: string;
|
|
57
|
-
label: string;
|
|
58
|
-
materialFunction: MatchMaterialFunction;
|
|
59
|
-
/** The detector's catalog category answer, when it named one. */
|
|
60
|
-
categoryHint?: string;
|
|
61
|
-
/** Detector confidence, always within [0, 1]. */
|
|
62
|
-
confidence: number;
|
|
63
|
-
description?: string;
|
|
64
|
-
boundingBox: MatchBoundingBox;
|
|
65
|
-
/** JPEG data-URI crop used for Match retrieval — the thumbnail to show. */
|
|
66
|
-
cropDataUri?: string;
|
|
67
|
-
/** The `construction_methods` dictionary term the detector's finish names. */
|
|
68
|
-
construction?: string;
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* One surface's matching state and its ranked results. The same `surface.id`
|
|
72
|
-
* arrives repeatedly as the run progresses (`matching` → `complete` / `error`);
|
|
73
|
-
* render by replacing on id rather than appending.
|
|
74
|
-
*
|
|
75
|
-
* A `complete` surface can arrive TWICE: the first frame delivers its finished
|
|
76
|
-
* results as soon as they exist, and a second repeats them unchanged with the
|
|
77
|
-
* verifier's per-candidate verdicts attached (`senseCheck`).
|
|
78
|
-
* Replacing on id handles both; the results never change between them, so
|
|
79
|
-
* nothing a user is looking at moves when the second lands.
|
|
80
|
-
*
|
|
81
|
-
* `results` and `inferredCategories` are always present on a yielded event: the
|
|
82
|
-
* canonical schema defaults each to `[]`, and the reader fills them when the
|
|
83
|
-
* server omits them, so neither ever arrives as `undefined`.
|
|
84
|
-
*/
|
|
85
|
-
/**
|
|
86
|
-
* What a Match actually compared, so a consumer can tell "the catalogue holds
|
|
87
|
-
* nothing close" from "everything ranked badly" (MG-1031). Without it both
|
|
88
|
-
* arrive as an empty list and the difference is unrecoverable.
|
|
89
|
-
*
|
|
90
|
-
* UNITS: `qualityFloor` and `bestRejected` are absolute image-arm cosines in
|
|
91
|
-
* [0,1] — the same unit as each result's `confidence` — so they belong on one
|
|
92
|
-
* axis. `poolSize` and `droppedBelowFloor` are counts and belong on neither.
|
|
93
|
-
*/
|
|
94
|
-
export type MatchComparison = {
|
|
95
|
-
/** Candidates retrieved before the quality floor and product dedup. */
|
|
96
|
-
poolSize: number;
|
|
97
|
-
/** How many of those the quality floor rejected. */
|
|
98
|
-
droppedBelowFloor: number;
|
|
99
|
-
/** The floor they were held to, as an absolute image cosine in [0,1]. */
|
|
100
|
-
qualityFloor: number;
|
|
101
|
-
/**
|
|
102
|
-
* The closest REJECTED candidate, same unit as `qualityFloor`. Absent when
|
|
103
|
-
* nothing was rejected, or when the rejects carried no readable signal.
|
|
104
|
-
*/
|
|
105
|
-
bestRejected?: number;
|
|
106
|
-
};
|
|
107
|
-
export type MatchSurfaceResult = {
|
|
108
|
-
surface: MatchDetectedSurface;
|
|
109
|
-
status: MatchSurfaceStatus;
|
|
110
|
-
results: SearchResultItem[];
|
|
111
|
-
inferredCategories: MatchCategoryInference[];
|
|
112
|
-
/** What this surface compared against. Absent means the server did not report it. */
|
|
113
|
-
comparison?: MatchComparison;
|
|
114
|
-
/**
|
|
115
|
-
* When `results` is empty, WHICH STAGE is responsible. Absent when the
|
|
116
|
-
* surface returned rows, and absent on servers older than this field.
|
|
117
|
-
*
|
|
118
|
-
* - `empty_pool` — nothing eligible was retrieved. A fact about the
|
|
119
|
-
* catalogue under the corpus scope in force.
|
|
120
|
-
* - `quality_floor` — candidates WERE retrieved and every one was rejected.
|
|
121
|
-
* A fact about the engine, not the catalogue.
|
|
122
|
-
* - `unattributed` — no comparison receipt survived to attribute from.
|
|
123
|
-
*
|
|
124
|
-
* The distinction is the point: "we found nothing you can buy" and "we found
|
|
125
|
-
* things and declined them all" are the same empty list and different
|
|
126
|
-
* findings, and only the first belongs on a "nothing available here yet"
|
|
127
|
-
* state.
|
|
128
|
-
*/
|
|
129
|
-
emptyReason?: "empty_pool" | "quality_floor" | "unattributed";
|
|
130
|
-
/**
|
|
131
|
-
* The verifier's reading of each candidate, when it ran.
|
|
132
|
-
*
|
|
133
|
-
* ABSENT means the stage did not run — it is opt-out, and the swatch route
|
|
134
|
-
* never runs it — OR that it is still running, which `senseCheckPending`
|
|
135
|
-
* distinguishes. Neither is the same as every candidate abstaining, and a
|
|
136
|
-
* consumer must not conflate them.
|
|
137
|
-
*
|
|
138
|
-
* `abstained` is NOT a soft rejection: it means the candidate was not judged
|
|
139
|
-
* (no image, no answer, or the judge was unavailable). Never render an
|
|
140
|
-
* abstention as a negative signal about the material.
|
|
141
|
-
*/
|
|
142
|
-
senseCheck?: MatchSenseCheckCell[];
|
|
143
|
-
/**
|
|
144
|
-
* TRUE on the interim frame that delivers finished results while the verifier
|
|
145
|
-
* is still reading them. Render the rows immediately. The follow-up frame
|
|
146
|
-
* carries the SAME rows with verdicts attached, settled once into verdict
|
|
147
|
-
* bands (confirmed → abstained → rejected, stable within each band) — the
|
|
148
|
-
* page's one settling reorder. Nothing is ever removed.
|
|
149
|
-
*/
|
|
150
|
-
senseCheckPending?: boolean;
|
|
151
|
-
/**
|
|
152
|
-
* Per-candidate colour readings against this surface's own crop, when the
|
|
153
|
-
* colour re-rank ran. `results` are already ordered by the blended score when
|
|
154
|
-
* this is present; this array is the receipt for that order.
|
|
155
|
-
*/
|
|
156
|
-
colour?: MatchColourReading[];
|
|
157
|
-
/** The segment's own extracted palette — what the colour stage matched against. */
|
|
158
|
-
segmentPalette?: {
|
|
159
|
-
hex: string;
|
|
160
|
-
proportion: number;
|
|
161
|
-
}[];
|
|
162
|
-
/**
|
|
163
|
-
* One sentence of provenance a consumer may render verbatim, when the server
|
|
164
|
-
* sent one — e.g. the `colour_fallback` explanation carrying the refused
|
|
165
|
-
* sample's pixel size. Absent on ordinary surfaces.
|
|
166
|
-
*/
|
|
167
|
-
note?: string;
|
|
168
|
-
/** Present only on `status: "error"` — why this one surface failed. */
|
|
169
|
-
error?: string;
|
|
170
|
-
};
|
|
171
|
-
/** The verifier's reading of one candidate, keyed back to its variant. */
|
|
172
|
-
export type MatchSenseCheckCell = {
|
|
173
|
-
variantId: string;
|
|
174
|
-
verdict: MatchSenseCheckVerdict;
|
|
175
|
-
reason: string;
|
|
176
|
-
};
|
|
177
|
-
export declare const MATCH_SENSE_CHECK_VERDICTS: readonly ["confirmed", "rejected", "abstained"];
|
|
178
|
-
export type MatchSenseCheckVerdict = (typeof MATCH_SENSE_CHECK_VERDICTS)[number];
|
|
179
|
-
/** The terminal Match workflow result — every surface in its final state. */
|
|
180
|
-
/**
|
|
181
|
-
* How a Match run ended. `no_surfaces` means the detector worked and found no
|
|
182
|
-
* material in the photo — a finding, not a failure. Branch on this rather than
|
|
183
|
-
* on an error message. Absent means `matched`.
|
|
184
|
-
*/
|
|
185
|
-
export declare const MATCH_OUTCOMES: readonly ["matched", "no_surfaces"];
|
|
186
|
-
export type MatchOutcome = (typeof MATCH_OUTCOMES)[number];
|
|
187
|
-
export type MatchWorkflowResult = {
|
|
188
|
-
/**
|
|
189
|
-
* Result attribution (MG-1131) — `responseId` (the same value as the run's
|
|
190
|
-
* `X-Request-Id` header), `basis: "match"`, and `issuedAt`. Every item in
|
|
191
|
-
* `results` and in each `surfaces[].results` carries a matching `resultId`.
|
|
192
|
-
*
|
|
193
|
-
* A surface's hits arrive twice — on its own `surface` frame and again here —
|
|
194
|
-
* and both times with the SAME `resultId`, so a consumer that stored the
|
|
195
|
-
* first recognises the second rather than double-counting it.
|
|
196
|
-
*
|
|
197
|
-
* ABSENT only from a response produced by a server predating MG-1131.
|
|
198
|
-
*/
|
|
199
|
-
attribution?: ResponseAttribution;
|
|
200
|
-
imageType: MatchImageType;
|
|
201
|
-
/** How the run ended. Absent means `matched`. */
|
|
202
|
-
outcome?: MatchOutcome;
|
|
203
|
-
surfaces: MatchSurfaceResult[];
|
|
204
|
-
/** Present for swatch / single-surface runs that skip decompose. */
|
|
205
|
-
results?: SearchResultItem[];
|
|
206
|
-
inferredCategories?: MatchCategoryInference[];
|
|
207
|
-
/**
|
|
208
|
-
* How the run ended, counted rather than inferred. `surfacesFailed > 0` with
|
|
209
|
-
* no results is a broken run; zero failures with no results is a genuine
|
|
210
|
-
* "nothing above the floor". Do not fold `surfaces[]` to tell those apart.
|
|
211
|
-
*/
|
|
212
|
-
totals: MatchRunTotals;
|
|
213
|
-
/**
|
|
214
|
-
* Whole-image palette matches, sent ONLY when an installation photo yielded
|
|
215
|
-
* no usable surfaces at all. These match the image's overall palette — they
|
|
216
|
-
* are not material identifications, and the note says so. A consumer that
|
|
217
|
-
* ignores this field sees exactly the empty run it saw before the field
|
|
218
|
-
* existed.
|
|
219
|
-
*/
|
|
220
|
-
paletteMatches?: {
|
|
221
|
-
results: SearchResultItem[];
|
|
222
|
-
palette: {
|
|
223
|
-
hex: string;
|
|
224
|
-
proportion: number;
|
|
225
|
-
}[];
|
|
226
|
-
note: string;
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* What a SWATCH run compared against — a swatch detects no surfaces, so it has
|
|
230
|
-
* nowhere else to put this. A scene run reports per surface instead.
|
|
231
|
-
*/
|
|
232
|
-
comparison?: MatchComparison;
|
|
233
|
-
};
|
|
234
|
-
/** Progress narration for the phase the workflow just entered. */
|
|
235
|
-
export type MatchStreamStepEvent = {
|
|
236
|
-
type: "step";
|
|
237
|
-
step: MatchWorkflowStep;
|
|
238
|
-
message: string;
|
|
239
|
-
};
|
|
240
|
-
/** The image type the classify step settled on. */
|
|
241
|
-
export type MatchStreamClassifiedEvent = {
|
|
242
|
-
type: "classified";
|
|
243
|
-
imageType: MatchImageType;
|
|
244
|
-
};
|
|
245
|
-
/** Every surface the decompose step found, before any of them has matched. */
|
|
246
|
-
export type MatchStreamSurfacesEvent = {
|
|
247
|
-
type: "surfaces";
|
|
248
|
-
surfaces: MatchDetectedSurface[];
|
|
249
|
-
};
|
|
250
|
-
/**
|
|
251
|
-
* The run's tally at the moment a `surface` event was emitted, so a consumer
|
|
252
|
-
* reads the server's arithmetic rather than reimplementing it.
|
|
253
|
-
*
|
|
254
|
-
* A FAILED surface is the case this exists to settle: failing is a way of
|
|
255
|
-
* RESOLVING. An errored surface counts in `surfacesResolved` (it will never be
|
|
256
|
-
* reported again), counts again in `surfacesFailed`, and adds nothing to
|
|
257
|
-
* `matchesSoFar`. `surfacesResolved === surfacesDetected` is therefore the
|
|
258
|
-
* correct "the run is done" test, and never stalls at 3/4 on a failure.
|
|
259
|
-
*/
|
|
260
|
-
export type MatchRunTotals = {
|
|
261
|
-
/** Surfaces the decompose step found. The denominator; fixed for the run. */
|
|
262
|
-
surfacesDetected: number;
|
|
263
|
-
/** Surfaces that reached a terminal state — `complete` OR `error`. */
|
|
264
|
-
surfacesResolved: number;
|
|
265
|
-
/** Of those resolved, how many ended in `error`. Always ≤ `surfacesResolved`. */
|
|
266
|
-
surfacesFailed: number;
|
|
267
|
-
/** Result items accumulated across every surface resolved so far. */
|
|
268
|
-
matchesSoFar: number;
|
|
269
|
-
};
|
|
270
|
-
/** One surface's state changed — the frame that makes Match progressive. */
|
|
271
|
-
export type MatchStreamSurfaceEvent = {
|
|
272
|
-
type: "surface";
|
|
273
|
-
surface: MatchSurfaceResult;
|
|
274
|
-
/** The run's tally as of this frame. Always present on a `surface` event. */
|
|
275
|
-
totals: MatchRunTotals;
|
|
276
|
-
};
|
|
277
|
-
/**
|
|
278
|
-
* CONNECTION LIVENESS ONLY — never progress. Proxies and load balancers kill
|
|
279
|
-
* idle connections, so the server sends this when the stream has been quiet, and
|
|
280
|
-
* a client can tell a slow run from a dropped one. It carries no payload, and no
|
|
281
|
-
* consumer should treat it as a state change: do not advance a step, reset a
|
|
282
|
-
* no-progress watchdog, or count it towards anything.
|
|
283
|
-
*/
|
|
284
|
-
export type MatchStreamHeartbeatEvent = {
|
|
285
|
-
type: "heartbeat";
|
|
286
|
-
};
|
|
287
|
-
/** Terminal: the whole run finished and carries its assembled result. */
|
|
288
|
-
export type MatchStreamCompleteEvent = {
|
|
289
|
-
type: "complete";
|
|
290
|
-
result: MatchWorkflowResult;
|
|
291
|
-
};
|
|
292
|
-
/** Terminal: the run failed as a whole (a single surface failing is not this). */
|
|
293
|
-
export type MatchStreamErrorEvent = {
|
|
294
|
-
type: "error";
|
|
295
|
-
message: string;
|
|
296
|
-
/**
|
|
297
|
-
* `upstream_unavailable`: a provider (vision, embedding, vector index) could
|
|
298
|
-
* not answer, so nothing was looked at and a retry may succeed. `failed`: the
|
|
299
|
-
* run broke on something else. Absent from servers older than MG-730.
|
|
300
|
-
*/
|
|
301
|
-
reason?: MatchErrorReason;
|
|
302
|
-
/** True only for `upstream_unavailable`. Absent from servers older than MG-730. */
|
|
303
|
-
retriable?: boolean;
|
|
304
|
-
};
|
|
305
|
-
/** One frame of the Match progress stream, discriminated by `type`. */
|
|
306
|
-
export type MatchStreamEvent = MatchStreamStepEvent | MatchStreamClassifiedEvent | MatchStreamSurfacesEvent | MatchStreamSurfaceEvent | MatchStreamHeartbeatEvent | MatchStreamCompleteEvent | MatchStreamErrorEvent;
|