@callimacus/thamyr-shopify 4.17.2 → 4.17.3
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/CHANGELOG.core.md +7 -0
- package/CHANGELOG.md +14 -0
- package/dist/esm/index.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.core.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [4.17.3](https://github.com/callimacus/thamyr-sdk/compare/thamyr-core-v4.17.2...thamyr-core-v4.17.3) (2026-11-03)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Miscellaneous Chores
|
|
10
|
+
|
|
11
|
+
* **thamyr-core:** Synchronize thamyr versions
|
|
12
|
+
|
|
6
13
|
## [4.17.2](https://github.com/callimacus/thamyr-sdk/compare/thamyr-core-v4.17.1...thamyr-core-v4.17.2) (2026-11-01)
|
|
7
14
|
|
|
8
15
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.17.3](https://github.com/callimacus/thamyr-sdk/compare/thamyr-shopify-v4.17.2...thamyr-shopify-v4.17.3) (2026-11-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **deps:** vitest 5.1.0, @tanstack/react-query 5.105.3 ([#877](https://github.com/callimacus/thamyr-sdk/issues/877)) ([2cd51a2](https://github.com/callimacus/thamyr-sdk/commit/2cd51a2837421048535d1bf1d2db3587c04d8eb6))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* devDependencies
|
|
15
|
+
* @callimacus/thamyr-core bumped from ^4.17.2 to ^4.17.3
|
|
16
|
+
|
|
3
17
|
## [4.17.2](https://github.com/callimacus/thamyr-sdk/compare/thamyr-shopify-v4.17.1...thamyr-shopify-v4.17.2) (2026-11-01)
|
|
4
18
|
|
|
5
19
|
|
package/dist/esm/index.js
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* See LICENSE.md for the full terms.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
const e="4.17.2",t={fg:{property:"--cal-fg",kind:"color"},bg:{property:"--cal-bg",kind:"color"},bodyFont:{property:"--cal-font-body",kind:"font"},bodyWeight:{property:"--cal-font-body-weight",kind:"keyword"},bodyStyle:{property:"--cal-font-body-style",kind:"keyword"},bodySize:{property:"--cal-body-size",kind:"length"},headingFont:{property:"--cal-font-heading",kind:"font"},headingWeight:{property:"--cal-font-heading-weight",kind:"keyword"},headingStyle:{property:"--cal-font-heading-style",kind:"keyword"},headingCase:{property:"--cal-heading-transform",kind:"keyword"},buttonBg:{property:"--cal-button-bg",kind:"color"},buttonFg:{property:"--cal-button-fg",kind:"color"},buttonBorderColor:{property:"--cal-button-border-color",kind:"color"},buttonBorderWidth:{property:"--cal-button-border-width",kind:"length"},buttonRadius:{property:"--cal-radius-button",kind:"length"},buttonCase:{property:"--cal-button-transform",kind:"keyword"},buttonSpacing:{property:"--cal-button-letter-spacing",kind:"length"},buttonFont:{property:"--cal-font-button",kind:"font"},buttonWeight:{property:"--cal-font-button-weight",kind:"keyword"},secondaryFg:{property:"--cal-button2-fg",kind:"color"},mediaRadius:{property:"--cal-radius-media",kind:"length"},cardRadius:{property:"--cal-radius-card",kind:"length"},pageWidth:{property:"--cal-page-width",kind:"length"}},o={color:/^(?:#[\da-f]{3,8}|transparent|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\([\s\d%+,\-./a-z]{1,80}\))$/iu,font:/^[\p{Letter}\p{Number} "',\-_]{1,200}$/u,length:/^(?:normal|none|-?(?:\d+(?:\.\d*)?|\.\d+)(?:px|rem|em|%|ch|vw)?)$/iu,keyword:/^(?:normal|bold|bolder|lighter|italic|oblique|none|uppercase|lowercase|capitalize|[1-9]\d{0,2}|1000)$/iu};function n(e,t){return t.length<=200&&o[e].test(t.trim())}function s(e){return Object.hasOwn(t,e)}function r(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const o={};for(const[r,a]of Object.entries(e)){if("string"!=typeof a||!s(r)||!n(t[r].kind,a))return;o[r]=a.trim()}return o}function a(e){return Object.entries(e).filter(e=>s(e[0])&&"string"==typeof e[1]).map(([e,o])=>`${t[e].property}:${o}`).join(";")}const i=/^#(?<digits>[\da-f]{3,8})$/u,p=/^rgba?\((?<channels>[^)]*)\)$/u;function d(e){const t=e.trim().toLowerCase(),o=i.exec(t)?.groups?.digits;if(void 0!==o){const e=o.length<=4?[...o].map(e=>e+e).join(""):o;if(6!==e.length&&8!==e.length)return;const t=t=>Number.parseInt(e.slice(t,t+2),16);return[t(0),t(2),t(4),8===e.length?t(6)/255:1]}const n=p.exec(t)?.groups?.channels?.split(/[\s,/]+/u).filter(e=>""!==e);if(void 0===n||n.length<3||n.length>4)return;const[s=NaN,r=NaN,a=NaN,d=1]=n.map((e,t)=>function(e,t){const o=Number(e.endsWith("%")?e.slice(0,-1):e);return e.endsWith("%")?3===t?o/100:2.55*o:o}(e,t));return[s,r,a,d].some(e=>Number.isNaN(e))?void 0:[s,r,a,d]}function h([e,t,o]){const n=e=>{const t=e/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4};return.2126*n(e)+.7152*n(t)+.0722*n(o)}function c(e,t){return(Math.max(h(e),h(t))+.05)/(Math.min(h(e),h(t))+.05)}function l(e){const t=void 0===e.bg?void 0:d(e.bg),o=void 0===e.buttonBg?void 0:d(e.buttonBg),n=void 0!==o&&o[3]>.5?o:t,s=void 0===e.buttonFg?void 0:d(e.buttonFg);if(void 0===n||void 0===s)return e;const r=c(s,n);if(r>=3)return e;let a;for(const t of[e.fg,e.bg]){const e=void 0===t?void 0:d(t),o=void 0===e?0:c(e,n);void 0!==t&&o>(a?.ratio??r)&&(a={value:t,ratio:o})}return void 0===a?e:{...e,buttonFg:a.value}}const u="product_browse",m=[{label:"solve_problem",description:"Describes a problem to solve or a situation to handle, rather than a kind of product: something that bothers them, a need to meet, an occasion to prepare for",examples:["my skin gets dry in winter","I am always cold at my desk","my feet hurt after a long day","how do I keep my kitchen tidy","what do I need for a first camping trip","my old one keeps breaking"]},{label:"material_info",description:"Asks what one material, ingredient or technology is, how it works or how it feels",examples:["what is merino wool?","how does this waterproof membrane work","is linen soft","what is hyaluronic acid","what does recycled polyester feel like","is stainless steel better than aluminium"]},{label:"size_or_care",description:"Asks about sizes, fit, dimensions, washing or care of a product",examples:["which size should I get?","do these run small?","how do I wash it?","what are the dimensions","can it go in the dishwasher","will it fit in a carry-on"]},{label:"compare_items",description:"Asks to compare two named products or ranges side by side, or which of two is better",examples:["which is better, the classic or the pro?","difference between the two jackets","linen vs cotton","the small one or the large one?","which is warmer, the wool or the down"]},{label:"store_info",description:"Asks about the store itself rather than its products: shipping and delivery, returns and exchanges, payment, privacy, terms, how to get in touch, or who is behind the store",examples:["what is your return policy?","how long does shipping take","do you ship abroad","can I exchange a gift","how do I contact you","who is behind the brand"]},{label:"inspiration",description:"Wants ideas or something to read rather than a product: tips, how-tos, styling or usage ideas, stories from the store's journal or blog",examples:["any tips for layering in winter","how should I style a linen shirt","ideas for a cosy bedroom","do you have a blog","how are your products made","what is in season right now"]},{label:u,description:"Looks for a kind of product, a style, a colour or a gift, with no problem to solve, material question, comparison or question about the store",examples:["show me what is new","I need a new bag","something in green","a gift for my mom","your best sellers","something for the weekend"]}],y=Object.freeze(m.map(e=>e.label));function f(e={}){return{category:"need",categoryDescription:"What kind of help the shopper needs: a problem to solve, what a material is, sizes or care, a comparison of two products, the store's own pages and policies, ideas to read, or simply looking for a kind of product",labels:m.map(t=>{const o=e[t.label];return{...t,examples:o&&o.length>0?[...o]:[...t.examples]}})}}const w={type:"not",value:{type:"receptorIs",value:"store_info"}};function g(e){return JSON.stringify(e)}const k={type:"string"};function b(e){return{type:"object",properties:e,required:Object.keys(e),additionalProperties:!1}}function v(e,t,o,n){return{specVersion:2,block:{type:e,data:t},contents:o,when:n,order:0}}function x(e){return[`You turn a shopper's message into a short product search query for ${e.name}, a store that sells ${e.catalogue}.`,"Output 1 to 4 lowercase words: the kind of product, the material or technology if one is named, and at most one size, colour or quality",'(examples: "linen shirt", "wool blanket queen", "black leather bag", "waterproof jacket").','When the message follows up on the chat history ("which of those", "in black", "cheaper ones", "for my partner"),',"keep the product type or material the earlier messages were about and add the new detail:",'after "what is merino?", "which of those come in navy?" becomes "merino navy".',"When the shopper describes a need or a problem without naming a kind of product, keep the query broad instead of guessing one product type:",'"I am always cold" becomes "warm layers", "something to relax in at home" becomes "loungewear".',"Output only the query, with no punctuation."].join(" ")}function q(e){return[`You turn a shopper's message into a short search query for the pages, policies and journal articles of ${e.name}, a store that sells ${e.catalogue}.`,'Output 1 to 5 lowercase words naming the topic (examples: "return policy", "shipping times abroad", "contact", "layering for winter", "linen care").','When the message follows up on the chat history ("and for sale items?", "how long does that take?"),',"keep the topic the earlier messages were about and add the new detail.","Output only the query, with no punctuation."].join(" ")}function j(e){return{id:"query",kind:"text",useDemosthenesTone:!1,output:{kind:"text"},template:"{{input.value}}",systemPrompt:e,useKb:!1}}function $(e){return{key:"editorialHero",name:"Storefront spread",prompt:"The editorial opening of the composed page: an eyebrow, a headline and a one-line dek over a photo of the best-matching product.",description:"An editorial opening for the page.",node:v("editorialHero",{query:"",lead:[],copy:{eyebrow:"",headline:"",dek:""}},[j(x(e)),{id:"lead",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.query}}"},{id:"copy",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You write the opening of an editorial page that ${e.name}, a store for ${e.catalogue}, composes for one shopper's question.`,'Return: eyebrow, 2 to 4 words naming the topic (for example "Staying warm");',`headline, at most 8 words, speaking to the shopper's need in ${e.name}'s calm, confident voice, with no product names, no question mark and no exclamation mark;`,"dek, one sentence of at most 22 words saying what the page gathers for them.","Write the eyebrow and headline in sentence case (capitalise only the first word and proper names). Use only facts from the context."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({eyebrow:k,headline:k,dek:k}))}}],w)}}function I(e){return{key:"storefrontReply",name:"Storefront reply",prompt:"The written answer to whatever the shopper asked, two to four short sentences in the store's voice, streamed as it is written. Useful on every question.",description:"The answer, written out.",node:v("storefrontReply",{text:""},[{id:"text",kind:"demosthenes",streaming:!0,template:[`Answer the shopper in two to four short sentences, in ${e.name}'s voice, from what ${e.name} sells and what the knowledge base says.`,"If this follows up on an earlier question, build on that conversation instead of starting over.","Point to the one thing worth looking at first. The shopper said: {{input.value}}"].join(" ")}],{type:"always"})}}function S(e){return{key:"storefrontPicks",name:"Storefront selection",prompt:["Products from the catalogue that fit what the shopper asked for, found with a short product query derived from the message and the conversation.","Use on every question that could be answered with products."].join(" "),description:"Products that match the request.",node:v("storefrontPicks",{query:"",picks:[]},[j(x(e)),{id:"picks",kind:"skesis",min:1,take:8,kinds:["product"],template:"{{content.query}}"}],w)}}function T(e){return{key:"collectionGrid",name:"Storefront selection collections",prompt:[`The collections of ${e.name} that fit what the shopper is looking for, each a tile that opens the collection.`,"Use on questions that browse for a kind of product, a style, an occasion or ideas."].join(" "),description:"Collections that match the request.",node:v("collectionGrid",{query:"",collections:[]},[j(x(e)),{id:"collections",kind:"skesis",min:1,take:4,kinds:["collection"],template:"{{content.query}}"}],{type:"receptorAny",value:[u,"inspiration"]})}}function z(e){return{key:"storyCards",name:"Storefront topic stories",prompt:`Articles from ${e.name}'s journal that help with what the shopper asked (guides, ideas, stories), each a card that opens the article.`,description:"Articles from the store's journal.",node:v("storyCards",{query:"",stories:[]},[j(q(e)),{id:"stories",kind:"skesis",min:1,take:3,kinds:["article"],template:"{{content.query}}"}],{type:"receptorAny",value:["inspiration","solve_problem"]})}}function A(e){return{key:"pageAnswer",name:"Storefront reply from store pages",prompt:[`What ${e.name}'s own pages and policies say on the shopper's question (shipping, returns, payment, privacy, contact, the store itself),`,"in the store's own words, with a link to the page."].join(" "),description:"The store's own page or policy on the question.",node:v("pageAnswer",{query:"",pages:[]},[j(q(e)),{id:"pages",kind:"documents",type:"text",filter:!1,knowledgeScope:"excludeInternal",min:1,take:3,template:"{{content.query}}"}],{type:"receptorIs",value:"store_info"})}}function W(e){const t=b({title:k,body:k,shopFor:k});return{key:"problemGuide",name:"Storefront topic solve a problem",prompt:`A step-by-step guide for a problem the shopper wants to solve, each step tied to the kind of ${e.name} product that helps.`,description:"A guide to solving the shopper's problem.",node:v("problemGuide",{guide:{title:"",steps:[]}},[{id:"guide",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You write a short, practical guide for a ${e.name} shopper who has a problem to solve, using only ${e.name}'s products and the facts in the context.`,"Return a title of at most 7 words and 3 or 4 steps in the order the shopper should take them.","Each step has: title (at most 5 words);",`body (one or two sentences, at most 35 words, naming the ${e.name} product or technology that helps and why);`,"shopFor (a 1 to 3 word product search query for that step).","Give no medical, legal or safety advice."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({title:k,steps:{type:"array",items:t,minItems:3,maxItems:4}}))}}],{type:"receptorIs",value:"solve_problem"})}}function P(e){return{key:"materialStory",name:"Storefront topic material",prompt:`Explains one material, ingredient or technology that ${e.name}'s products use, with three facts and the products made of it.`,description:"What a material is and the products made of it.",node:v("materialStory",{story:{material:"",headline:"",body:"",facts:[]},products:[]},[{id:"story",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You explain one material, ingredient or technology that ${e.name} uses, for a shopper who asked about it, using only the facts in the context.`,`Return: material (its name as ${e.name}'s products use it, 1 to 4 words); headline (at most 8 words on how it feels or what it does, no question mark);`,"body (2 or 3 sentences, at most 60 words: what it is, how it works, how it feels);",`facts (exactly 3 short facts of at most 12 words each, such as which ${e.name} products use it).`,"If the shopper mentions several, choose the one they ask about first."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({material:k,headline:k,body:k,facts:{type:"array",items:k,minItems:3,maxItems:3}}))}},{id:"products",kind:"skesis",min:0,take:3,kinds:["product"],template:"{{content.story.material}}"}],{type:"receptorIs",value:"material_info"})}}function _(e){return{key:"sizeCare",name:"Storefront topic size and care",prompt:"Questions and answers on sizes, fit, dimensions, washing and care.",description:"Answers about sizes, fit and care.",node:v("sizeCare",{faq:[]},[{id:"faq",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You answer a ${e.name} shopper's question about sizes, fit or care as a short set of questions and answers, using only the facts in the context.`,"Return 3 to 5 items. The first answers exactly what the shopper asked; the others answer the next questions they are likely to have.","Each answer is concrete and at most 40 words (dimensions, which size to pick, what the product or its care label says).","When the context does not say, tell them to check the care label or the size details on the product page; never invent care instructions."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({question:k,answer:k}),minItems:3,maxItems:5})}}],{type:"receptorIs",value:"size_or_care"})}}function F(e){const t=b({aspect:k,first:k,second:k});return{key:"compareSet",name:"Storefront topic compare",prompt:"Two named products or ranges side by side, with the differences that matter and who each one suits.",description:"A side-by-side comparison of two products.",node:v("compareSet",{pair:{first:"",second:""},first:[],second:[],verdict:{summary:"",rows:[]}},[{id:"pair",kind:"text",useKb:!1,useDemosthenesTone:!1,systemPrompt:[`The shopper wants to compare two ${e.name} products or ranges.`,"Return the two things being compared as short product search queries of 2 to 5 lowercase words each,",'using the product names the shopper or the conversation used (for example "classic wool coat" and "lightweight down coat").'].join(" "),template:"{{input.value}}",output:{kind:"json",schemaJson:g(b({first:k,second:k}))}},{id:"first",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.pair.first}}"},{id:"second",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.pair.second}}"},{id:"verdict",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You compare two ${e.name} products for a shopper, using only the facts in the context and the two retrieved products.`,"Return: summary (one or two sentences, at most 40 words, saying who each one suits);",'rows (3 to 5 rows, each with aspect, 1 to 3 words such as "Feel", "Weight", "Fit", "Price", "Sizes", and a short value for first and for second, at most 10 words each).',"Mention no product other than the two."].join(" "),template:'The shopper said: "{{input.value}}". First: {{content.pair.first}} (retrieved: {{content.first}}). Second: {{content.pair.second}} (retrieved: {{content.second}}).',output:{kind:"json",schemaJson:g(b({summary:k,rows:{type:"array",items:t,minItems:3,maxItems:5}}))}}],{type:"receptorIs",value:"compare_items"})}}function N(e){return{key:"completeSet",name:"Storefront tier two complete the set",prompt:"Complete the set: three companion products from other product types that go with what the shopper is looking for, each with a one-line reason.",description:"Companion products that complete the look.",node:v("completeSet",{companions:[]},[{id:"companions",kind:"text",useKb:!1,useDemosthenesTone:!0,systemPrompt:[`You suggest companion products from ${e.name} that complete what the shopper is looking for, the way a stylist completes a look.`,"Return exactly 3 items, each from a different product type than the one the shopper asked for.","Each item has: query (a 1 to 3 word product search query); why (at most 12 words on why it goes with what they asked for).",`Use only product types ${e.name} sells: ${e.catalogue}.`].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({query:k,why:k}),minItems:3,maxItems:3})}},{id:"companionHits",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{item.query}}",each:{fromId:"companions",arrayPath:"companions",assignField:"product",pick:"first",extend:!1}}],{type:"receptorAny",value:[u,"solve_problem"]})}}function C(e){return{key:"followUps",name:"Storefront tier two follow ups",prompt:"Three self-contained next questions the shopper can tap to continue the conversation.",description:"Suggested next questions.",node:v("followUps",{next:[]},[{id:"next",kind:"text",useKb:!0,useDemosthenesTone:!1,systemPrompt:[`You suggest the three most useful next questions a ${e.name} shopper could ask after this one, written in the shopper's own voice.`,'Each item has: label (2 to 5 words for a button, for example "Warmer options");',"question (a complete question of at most 14 words that names the product or topic, so it makes sense on its own,",'for example "Which jackets are warm enough for winter?").',"Cover different directions: go deeper, a related product, a practical detail such as size or care.",`Ask only about what ${e.name} sells (${e.catalogue}) and the materials and brands in the context. Never mention anything else.`].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({label:k,question:k}),minItems:3,maxItems:3})}}],{type:"always"})}}function R(e){return[I(e),A(e),S(e),T(e),$(e),N(e),C(e),F(e),P(e),_(e),W(e),z(e)]}export{t as LOOK_TOKENS,u as NEED_DEFAULT_LABEL,y as NEED_LABELS,e as PACKAGE_VERSION,R as blockSpecs,l as guardLook,n as isLookValue,a as lookCss,f as needCategory,r as parseLook};
|
|
8
|
+
const e="4.17.3",t={fg:{property:"--cal-fg",kind:"color"},bg:{property:"--cal-bg",kind:"color"},bodyFont:{property:"--cal-font-body",kind:"font"},bodyWeight:{property:"--cal-font-body-weight",kind:"keyword"},bodyStyle:{property:"--cal-font-body-style",kind:"keyword"},bodySize:{property:"--cal-body-size",kind:"length"},headingFont:{property:"--cal-font-heading",kind:"font"},headingWeight:{property:"--cal-font-heading-weight",kind:"keyword"},headingStyle:{property:"--cal-font-heading-style",kind:"keyword"},headingCase:{property:"--cal-heading-transform",kind:"keyword"},buttonBg:{property:"--cal-button-bg",kind:"color"},buttonFg:{property:"--cal-button-fg",kind:"color"},buttonBorderColor:{property:"--cal-button-border-color",kind:"color"},buttonBorderWidth:{property:"--cal-button-border-width",kind:"length"},buttonRadius:{property:"--cal-radius-button",kind:"length"},buttonCase:{property:"--cal-button-transform",kind:"keyword"},buttonSpacing:{property:"--cal-button-letter-spacing",kind:"length"},buttonFont:{property:"--cal-font-button",kind:"font"},buttonWeight:{property:"--cal-font-button-weight",kind:"keyword"},secondaryFg:{property:"--cal-button2-fg",kind:"color"},mediaRadius:{property:"--cal-radius-media",kind:"length"},cardRadius:{property:"--cal-radius-card",kind:"length"},pageWidth:{property:"--cal-page-width",kind:"length"}},o={color:/^(?:#[\da-f]{3,8}|transparent|(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\([\s\d%+,\-./a-z]{1,80}\))$/iu,font:/^[\p{Letter}\p{Number} "',\-_]{1,200}$/u,length:/^(?:normal|none|-?(?:\d+(?:\.\d*)?|\.\d+)(?:px|rem|em|%|ch|vw)?)$/iu,keyword:/^(?:normal|bold|bolder|lighter|italic|oblique|none|uppercase|lowercase|capitalize|[1-9]\d{0,2}|1000)$/iu};function n(e,t){return t.length<=200&&o[e].test(t.trim())}function s(e){return Object.hasOwn(t,e)}function r(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const o={};for(const[r,a]of Object.entries(e)){if("string"!=typeof a||!s(r)||!n(t[r].kind,a))return;o[r]=a.trim()}return o}function a(e){return Object.entries(e).filter(e=>s(e[0])&&"string"==typeof e[1]).map(([e,o])=>`${t[e].property}:${o}`).join(";")}const i=/^#(?<digits>[\da-f]{3,8})$/u,p=/^rgba?\((?<channels>[^)]*)\)$/u;function d(e){const t=e.trim().toLowerCase(),o=i.exec(t)?.groups?.digits;if(void 0!==o){const e=o.length<=4?[...o].map(e=>e+e).join(""):o;if(6!==e.length&&8!==e.length)return;const t=t=>Number.parseInt(e.slice(t,t+2),16);return[t(0),t(2),t(4),8===e.length?t(6)/255:1]}const n=p.exec(t)?.groups?.channels?.split(/[\s,/]+/u).filter(e=>""!==e);if(void 0===n||n.length<3||n.length>4)return;const[s=NaN,r=NaN,a=NaN,d=1]=n.map((e,t)=>function(e,t){const o=Number(e.endsWith("%")?e.slice(0,-1):e);return e.endsWith("%")?3===t?o/100:2.55*o:o}(e,t));return[s,r,a,d].some(e=>Number.isNaN(e))?void 0:[s,r,a,d]}function h([e,t,o]){const n=e=>{const t=e/255;return t<=.03928?t/12.92:((t+.055)/1.055)**2.4};return.2126*n(e)+.7152*n(t)+.0722*n(o)}function c(e,t){return(Math.max(h(e),h(t))+.05)/(Math.min(h(e),h(t))+.05)}function l(e){const t=void 0===e.bg?void 0:d(e.bg),o=void 0===e.buttonBg?void 0:d(e.buttonBg),n=void 0!==o&&o[3]>.5?o:t,s=void 0===e.buttonFg?void 0:d(e.buttonFg);if(void 0===n||void 0===s)return e;const r=c(s,n);if(r>=3)return e;let a;for(const t of[e.fg,e.bg]){const e=void 0===t?void 0:d(t),o=void 0===e?0:c(e,n);void 0!==t&&o>(a?.ratio??r)&&(a={value:t,ratio:o})}return void 0===a?e:{...e,buttonFg:a.value}}const u="product_browse",m=[{label:"solve_problem",description:"Describes a problem to solve or a situation to handle, rather than a kind of product: something that bothers them, a need to meet, an occasion to prepare for",examples:["my skin gets dry in winter","I am always cold at my desk","my feet hurt after a long day","how do I keep my kitchen tidy","what do I need for a first camping trip","my old one keeps breaking"]},{label:"material_info",description:"Asks what one material, ingredient or technology is, how it works or how it feels",examples:["what is merino wool?","how does this waterproof membrane work","is linen soft","what is hyaluronic acid","what does recycled polyester feel like","is stainless steel better than aluminium"]},{label:"size_or_care",description:"Asks about sizes, fit, dimensions, washing or care of a product",examples:["which size should I get?","do these run small?","how do I wash it?","what are the dimensions","can it go in the dishwasher","will it fit in a carry-on"]},{label:"compare_items",description:"Asks to compare two named products or ranges side by side, or which of two is better",examples:["which is better, the classic or the pro?","difference between the two jackets","linen vs cotton","the small one or the large one?","which is warmer, the wool or the down"]},{label:"store_info",description:"Asks about the store itself rather than its products: shipping and delivery, returns and exchanges, payment, privacy, terms, how to get in touch, or who is behind the store",examples:["what is your return policy?","how long does shipping take","do you ship abroad","can I exchange a gift","how do I contact you","who is behind the brand"]},{label:"inspiration",description:"Wants ideas or something to read rather than a product: tips, how-tos, styling or usage ideas, stories from the store's journal or blog",examples:["any tips for layering in winter","how should I style a linen shirt","ideas for a cosy bedroom","do you have a blog","how are your products made","what is in season right now"]},{label:u,description:"Looks for a kind of product, a style, a colour or a gift, with no problem to solve, material question, comparison or question about the store",examples:["show me what is new","I need a new bag","something in green","a gift for my mom","your best sellers","something for the weekend"]}],y=Object.freeze(m.map(e=>e.label));function f(e={}){return{category:"need",categoryDescription:"What kind of help the shopper needs: a problem to solve, what a material is, sizes or care, a comparison of two products, the store's own pages and policies, ideas to read, or simply looking for a kind of product",labels:m.map(t=>{const o=e[t.label];return{...t,examples:o&&o.length>0?[...o]:[...t.examples]}})}}const w={type:"not",value:{type:"receptorIs",value:"store_info"}};function g(e){return JSON.stringify(e)}const k={type:"string"};function b(e){return{type:"object",properties:e,required:Object.keys(e),additionalProperties:!1}}function v(e,t,o,n){return{specVersion:2,block:{type:e,data:t},contents:o,when:n,order:0}}function x(e){return[`You turn a shopper's message into a short product search query for ${e.name}, a store that sells ${e.catalogue}.`,"Output 1 to 4 lowercase words: the kind of product, the material or technology if one is named, and at most one size, colour or quality",'(examples: "linen shirt", "wool blanket queen", "black leather bag", "waterproof jacket").','When the message follows up on the chat history ("which of those", "in black", "cheaper ones", "for my partner"),',"keep the product type or material the earlier messages were about and add the new detail:",'after "what is merino?", "which of those come in navy?" becomes "merino navy".',"When the shopper describes a need or a problem without naming a kind of product, keep the query broad instead of guessing one product type:",'"I am always cold" becomes "warm layers", "something to relax in at home" becomes "loungewear".',"Output only the query, with no punctuation."].join(" ")}function q(e){return[`You turn a shopper's message into a short search query for the pages, policies and journal articles of ${e.name}, a store that sells ${e.catalogue}.`,'Output 1 to 5 lowercase words naming the topic (examples: "return policy", "shipping times abroad", "contact", "layering for winter", "linen care").','When the message follows up on the chat history ("and for sale items?", "how long does that take?"),',"keep the topic the earlier messages were about and add the new detail.","Output only the query, with no punctuation."].join(" ")}function j(e){return{id:"query",kind:"text",useDemosthenesTone:!1,output:{kind:"text"},template:"{{input.value}}",systemPrompt:e,useKb:!1}}function $(e){return{key:"editorialHero",name:"Storefront spread",prompt:"The editorial opening of the composed page: an eyebrow, a headline and a one-line dek over a photo of the best-matching product.",description:"An editorial opening for the page.",node:v("editorialHero",{query:"",lead:[],copy:{eyebrow:"",headline:"",dek:""}},[j(x(e)),{id:"lead",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.query}}"},{id:"copy",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You write the opening of an editorial page that ${e.name}, a store for ${e.catalogue}, composes for one shopper's question.`,'Return: eyebrow, 2 to 4 words naming the topic (for example "Staying warm");',`headline, at most 8 words, speaking to the shopper's need in ${e.name}'s calm, confident voice, with no product names, no question mark and no exclamation mark;`,"dek, one sentence of at most 22 words saying what the page gathers for them.","Write the eyebrow and headline in sentence case (capitalise only the first word and proper names). Use only facts from the context."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({eyebrow:k,headline:k,dek:k}))}}],w)}}function I(e){return{key:"storefrontReply",name:"Storefront reply",prompt:"The written answer to whatever the shopper asked, two to four short sentences in the store's voice, streamed as it is written. Useful on every question.",description:"The answer, written out.",node:v("storefrontReply",{text:""},[{id:"text",kind:"demosthenes",streaming:!0,template:[`Answer the shopper in two to four short sentences, in ${e.name}'s voice, from what ${e.name} sells and what the knowledge base says.`,"If this follows up on an earlier question, build on that conversation instead of starting over.","Point to the one thing worth looking at first. The shopper said: {{input.value}}"].join(" ")}],{type:"always"})}}function S(e){return{key:"storefrontPicks",name:"Storefront selection",prompt:["Products from the catalogue that fit what the shopper asked for, found with a short product query derived from the message and the conversation.","Use on every question that could be answered with products."].join(" "),description:"Products that match the request.",node:v("storefrontPicks",{query:"",picks:[]},[j(x(e)),{id:"picks",kind:"skesis",min:1,take:8,kinds:["product"],template:"{{content.query}}"}],w)}}function T(e){return{key:"collectionGrid",name:"Storefront selection collections",prompt:[`The collections of ${e.name} that fit what the shopper is looking for, each a tile that opens the collection.`,"Use on questions that browse for a kind of product, a style, an occasion or ideas."].join(" "),description:"Collections that match the request.",node:v("collectionGrid",{query:"",collections:[]},[j(x(e)),{id:"collections",kind:"skesis",min:1,take:4,kinds:["collection"],template:"{{content.query}}"}],{type:"receptorAny",value:[u,"inspiration"]})}}function z(e){return{key:"storyCards",name:"Storefront topic stories",prompt:`Articles from ${e.name}'s journal that help with what the shopper asked (guides, ideas, stories), each a card that opens the article.`,description:"Articles from the store's journal.",node:v("storyCards",{query:"",stories:[]},[j(q(e)),{id:"stories",kind:"skesis",min:1,take:3,kinds:["article"],template:"{{content.query}}"}],{type:"receptorAny",value:["inspiration","solve_problem"]})}}function A(e){return{key:"pageAnswer",name:"Storefront reply from store pages",prompt:[`What ${e.name}'s own pages and policies say on the shopper's question (shipping, returns, payment, privacy, contact, the store itself),`,"in the store's own words, with a link to the page."].join(" "),description:"The store's own page or policy on the question.",node:v("pageAnswer",{query:"",pages:[]},[j(q(e)),{id:"pages",kind:"documents",type:"text",filter:!1,knowledgeScope:"excludeInternal",min:1,take:3,template:"{{content.query}}"}],{type:"receptorIs",value:"store_info"})}}function W(e){const t=b({title:k,body:k,shopFor:k});return{key:"problemGuide",name:"Storefront topic solve a problem",prompt:`A step-by-step guide for a problem the shopper wants to solve, each step tied to the kind of ${e.name} product that helps.`,description:"A guide to solving the shopper's problem.",node:v("problemGuide",{guide:{title:"",steps:[]}},[{id:"guide",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You write a short, practical guide for a ${e.name} shopper who has a problem to solve, using only ${e.name}'s products and the facts in the context.`,"Return a title of at most 7 words and 3 or 4 steps in the order the shopper should take them.","Each step has: title (at most 5 words);",`body (one or two sentences, at most 35 words, naming the ${e.name} product or technology that helps and why);`,"shopFor (a 1 to 3 word product search query for that step).","Give no medical, legal or safety advice."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({title:k,steps:{type:"array",items:t,minItems:3,maxItems:4}}))}}],{type:"receptorIs",value:"solve_problem"})}}function P(e){return{key:"materialStory",name:"Storefront topic material",prompt:`Explains one material, ingredient or technology that ${e.name}'s products use, with three facts and the products made of it.`,description:"What a material is and the products made of it.",node:v("materialStory",{story:{material:"",headline:"",body:"",facts:[]},products:[]},[{id:"story",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You explain one material, ingredient or technology that ${e.name} uses, for a shopper who asked about it, using only the facts in the context.`,`Return: material (its name as ${e.name}'s products use it, 1 to 4 words); headline (at most 8 words on how it feels or what it does, no question mark);`,"body (2 or 3 sentences, at most 60 words: what it is, how it works, how it feels);",`facts (exactly 3 short facts of at most 12 words each, such as which ${e.name} products use it).`,"If the shopper mentions several, choose the one they ask about first."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g(b({material:k,headline:k,body:k,facts:{type:"array",items:k,minItems:3,maxItems:3}}))}},{id:"products",kind:"skesis",min:0,take:3,kinds:["product"],template:"{{content.story.material}}"}],{type:"receptorIs",value:"material_info"})}}function _(e){return{key:"sizeCare",name:"Storefront topic size and care",prompt:"Questions and answers on sizes, fit, dimensions, washing and care.",description:"Answers about sizes, fit and care.",node:v("sizeCare",{faq:[]},[{id:"faq",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You answer a ${e.name} shopper's question about sizes, fit or care as a short set of questions and answers, using only the facts in the context.`,"Return 3 to 5 items. The first answers exactly what the shopper asked; the others answer the next questions they are likely to have.","Each answer is concrete and at most 40 words (dimensions, which size to pick, what the product or its care label says).","When the context does not say, tell them to check the care label or the size details on the product page; never invent care instructions."].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({question:k,answer:k}),minItems:3,maxItems:5})}}],{type:"receptorIs",value:"size_or_care"})}}function F(e){const t=b({aspect:k,first:k,second:k});return{key:"compareSet",name:"Storefront topic compare",prompt:"Two named products or ranges side by side, with the differences that matter and who each one suits.",description:"A side-by-side comparison of two products.",node:v("compareSet",{pair:{first:"",second:""},first:[],second:[],verdict:{summary:"",rows:[]}},[{id:"pair",kind:"text",useKb:!1,useDemosthenesTone:!1,systemPrompt:[`The shopper wants to compare two ${e.name} products or ranges.`,"Return the two things being compared as short product search queries of 2 to 5 lowercase words each,",'using the product names the shopper or the conversation used (for example "classic wool coat" and "lightweight down coat").'].join(" "),template:"{{input.value}}",output:{kind:"json",schemaJson:g(b({first:k,second:k}))}},{id:"first",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.pair.first}}"},{id:"second",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{content.pair.second}}"},{id:"verdict",kind:"text",useKb:!0,useDemosthenesTone:!0,systemPrompt:[`You compare two ${e.name} products for a shopper, using only the facts in the context and the two retrieved products.`,"Return: summary (one or two sentences, at most 40 words, saying who each one suits);",'rows (3 to 5 rows, each with aspect, 1 to 3 words such as "Feel", "Weight", "Fit", "Price", "Sizes", and a short value for first and for second, at most 10 words each).',"Mention no product other than the two."].join(" "),template:'The shopper said: "{{input.value}}". First: {{content.pair.first}} (retrieved: {{content.first}}). Second: {{content.pair.second}} (retrieved: {{content.second}}).',output:{kind:"json",schemaJson:g(b({summary:k,rows:{type:"array",items:t,minItems:3,maxItems:5}}))}}],{type:"receptorIs",value:"compare_items"})}}function N(e){return{key:"completeSet",name:"Storefront tier two complete the set",prompt:"Complete the set: three companion products from other product types that go with what the shopper is looking for, each with a one-line reason.",description:"Companion products that complete the look.",node:v("completeSet",{companions:[]},[{id:"companions",kind:"text",useKb:!1,useDemosthenesTone:!0,systemPrompt:[`You suggest companion products from ${e.name} that complete what the shopper is looking for, the way a stylist completes a look.`,"Return exactly 3 items, each from a different product type than the one the shopper asked for.","Each item has: query (a 1 to 3 word product search query); why (at most 12 words on why it goes with what they asked for).",`Use only product types ${e.name} sells: ${e.catalogue}.`].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({query:k,why:k}),minItems:3,maxItems:3})}},{id:"companionHits",kind:"skesis",min:0,take:1,kinds:["product"],template:"{{item.query}}",each:{fromId:"companions",arrayPath:"companions",assignField:"product",pick:"first",extend:!1}}],{type:"receptorAny",value:[u,"solve_problem"]})}}function C(e){return{key:"followUps",name:"Storefront tier two follow ups",prompt:"Three self-contained next questions the shopper can tap to continue the conversation.",description:"Suggested next questions.",node:v("followUps",{next:[]},[{id:"next",kind:"text",useKb:!0,useDemosthenesTone:!1,systemPrompt:[`You suggest the three most useful next questions a ${e.name} shopper could ask after this one, written in the shopper's own voice.`,'Each item has: label (2 to 5 words for a button, for example "Warmer options");',"question (a complete question of at most 14 words that names the product or topic, so it makes sense on its own,",'for example "Which jackets are warm enough for winter?").',"Cover different directions: go deeper, a related product, a practical detail such as size or care.",`Ask only about what ${e.name} sells (${e.catalogue}) and the materials and brands in the context. Never mention anything else.`].join(" "),template:'The shopper said: "{{input.value}}"',output:{kind:"json",schemaJson:g({type:"array",items:b({label:k,question:k}),minItems:3,maxItems:3})}}],{type:"always"})}}function R(e){return[I(e),A(e),S(e),T(e),$(e),N(e),C(e),F(e),P(e),_(e),W(e),z(e)]}export{t as LOOK_TOKENS,u as NEED_DEFAULT_LABEL,y as NEED_LABELS,e as PACKAGE_VERSION,R as blockSpecs,l as guardLook,n as isLookValue,a as lookCss,f as needCategory,r as parseLook};
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@callimacus/thamyr-shopify",
|
|
3
|
-
"version": "4.17.
|
|
3
|
+
"version": "4.17.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Callimacus storefront for Shopify, as an app embed on any theme: the browser runtime, renderers and look reader, and the setup specs and look checks core uses",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"lint": "eslint src"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@callimacus/thamyr-core": "^4.17.
|
|
39
|
+
"@callimacus/thamyr-core": "^4.17.3",
|
|
40
40
|
"eslint-config-xo": "^7.0.0",
|
|
41
41
|
"jsdom": "^30.1.3",
|
|
42
|
-
"vitest": "^5.0
|
|
42
|
+
"vitest": "^5.1.0"
|
|
43
43
|
}
|
|
44
44
|
}
|