@meuecommerce/frete-adapter-node 0.8.1 → 0.9.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.
@@ -8,7 +8,7 @@ const openAIResponsesAgentRunner_js_1 = require("./openAIResponsesAgentRunner.js
8
8
  * `L3` record so a prompt change can invalidate stale estimates in background
9
9
  * instead of at checkout.
10
10
  */
11
- exports.DIMENSION_PROMPT_VERSION = "2026-09-04.responses.v1";
11
+ exports.DIMENSION_PROMPT_VERSION = "2026-09-11.responses.v2-atributos";
12
12
  /**
13
13
  * Strict JSON schema for the response.
14
14
  *
@@ -29,8 +29,20 @@ const DIMENSIONS_SCHEMA = {
29
29
  length: { type: "number", description: "Comprimento em cm" },
30
30
  width: { type: "number", description: "Largura em cm" },
31
31
  height: { type: "number", description: "Altura em cm" },
32
+ attrs: {
33
+ type: "object",
34
+ description: "Como o produto ocupa espaço. Na dúvida, false — cada traço afrouxa o encaixe.",
35
+ properties: {
36
+ fragile: { type: "boolean", description: "Quebra se receber peso em cima (vidro, cerâmica, ovo)" },
37
+ compressible: { type: "boolean", description: "Cede quando espremido (roupa, tecido, espuma, travesseiro)" },
38
+ nestable: { type: "boolean", description: "Unidades iguais encaixam uma na outra (tigela, copo, cone, pote)" },
39
+ keepUpright: { type: "boolean", description: "Precisa viajar em pé (líquido, bolo, planta)" },
40
+ },
41
+ required: ["fragile", "compressible", "nestable", "keepUpright"],
42
+ additionalProperties: false,
43
+ },
32
44
  },
33
- required: ["name", "length", "width", "height"],
45
+ required: ["name", "length", "width", "height", "attrs"],
34
46
  additionalProperties: false,
35
47
  },
36
48
  },
@@ -54,8 +66,29 @@ function createPrompt(products, boxes, samples) {
54
66
  `🚨 LIMITES FÍSICOS OBRIGATÓRIOS:\n- Largura máxima: ${maxWidth}cm\n- Altura máxima: ${maxHeight}cm\n- Comprimento máximo: ${maxLength}cm\n(Maior caixa: ${box.name ?? "—"})\n\n` +
55
67
  `📦 PRODUTOS PARA ESTIMAR:\n${products.map((p, i) => `${i + 1}. ${p.name} - ${p.quantity}x (${p.weight}kg cada)`).join("\n")}\n` +
56
68
  samplesSection +
69
+ `\n🧱 COMO O PRODUTO OCUPA ESPAÇO (campo attrs, um por produto):\n` +
70
+ `- fragile: quebra se levar peso em cima — vidro, cerâmica, garrafa, ovo\n` +
71
+ `- compressible: cede quando espremido — roupa, tecido, espuma, travesseiro, pelúcia\n` +
72
+ `- nestable: unidades IGUAIS encaixam uma na outra — tigela, copo, cone, pote, vaso\n` +
73
+ `- keepUpright: precisa viajar em pé — líquido, tinta, bolo, planta\n` +
74
+ `Na dúvida responda false. Cada traço afrouxa o encaixe, e afrouxar errado faz o pacote não fechar.\n` +
57
75
  `\n⚠️ REGRAS: respeite os limites; preserve os nomes EXATOS; retorne length×width×height em cm.`);
58
76
  }
77
+ /**
78
+ * Só os traços verdadeiros, e nada quando não há nenhum.
79
+ *
80
+ * O schema obriga o modelo a responder os quatro booleanos, então quase todo
81
+ * produto volta com `{fragile:false, compressible:false, ...}`. Guardar isso é
82
+ * gravar ruído em cada linha da memória e, pior, apagar a diferença entre
83
+ * "sabemos que é um tijolo" e "não perguntamos" — que é justamente o que o
84
+ * empacotador precisa distinguir.
85
+ */
86
+ function attrsVerdadeiros(attrs) {
87
+ if (!attrs)
88
+ return null;
89
+ const so = Object.fromEntries(Object.entries(attrs).filter(([, v]) => v === true));
90
+ return Object.keys(so).length ? { attrs: so } : null;
91
+ }
59
92
  /** Apply the largest-box physical limits + a minimum-volume floor to AI output. */
60
93
  function validateAndOptimize(aiResult, products, boxes) {
61
94
  const box = largestBox(boxes);
@@ -84,6 +117,7 @@ function validateAndOptimize(aiResult, products, boxes) {
84
117
  length: Math.round(length * 10) / 10,
85
118
  width: Math.round(width * 10) / 10,
86
119
  height: Math.round(height * 10) / 10,
120
+ ...(attrsVerdadeiros(product.attrs) ?? {}),
87
121
  };
88
122
  });
89
123
  return { products: optimized };
@@ -25,7 +25,7 @@ type FetchLike = typeof globalThis.fetch;
25
25
  * `L3` record so a prompt change can invalidate stale estimates in background
26
26
  * instead of at checkout.
27
27
  */
28
- export declare const DIMENSION_PROMPT_VERSION = "2026-09-04.responses.v1";
28
+ export declare const DIMENSION_PROMPT_VERSION = "2026-09-11.responses.v2-atributos";
29
29
  export interface OpenAIDimensionEstimatorOptions {
30
30
  apiKey?: string;
31
31
  fetch?: FetchLike;
@@ -4,7 +4,7 @@ import { createOpenAIResponsesAgentRunner } from "./openAIResponsesAgentRunner.j
4
4
  * `L3` record so a prompt change can invalidate stale estimates in background
5
5
  * instead of at checkout.
6
6
  */
7
- export const DIMENSION_PROMPT_VERSION = "2026-09-04.responses.v1";
7
+ export const DIMENSION_PROMPT_VERSION = "2026-09-11.responses.v2-atributos";
8
8
  /**
9
9
  * Strict JSON schema for the response.
10
10
  *
@@ -25,8 +25,20 @@ const DIMENSIONS_SCHEMA = {
25
25
  length: { type: "number", description: "Comprimento em cm" },
26
26
  width: { type: "number", description: "Largura em cm" },
27
27
  height: { type: "number", description: "Altura em cm" },
28
+ attrs: {
29
+ type: "object",
30
+ description: "Como o produto ocupa espaço. Na dúvida, false — cada traço afrouxa o encaixe.",
31
+ properties: {
32
+ fragile: { type: "boolean", description: "Quebra se receber peso em cima (vidro, cerâmica, ovo)" },
33
+ compressible: { type: "boolean", description: "Cede quando espremido (roupa, tecido, espuma, travesseiro)" },
34
+ nestable: { type: "boolean", description: "Unidades iguais encaixam uma na outra (tigela, copo, cone, pote)" },
35
+ keepUpright: { type: "boolean", description: "Precisa viajar em pé (líquido, bolo, planta)" },
36
+ },
37
+ required: ["fragile", "compressible", "nestable", "keepUpright"],
38
+ additionalProperties: false,
39
+ },
28
40
  },
29
- required: ["name", "length", "width", "height"],
41
+ required: ["name", "length", "width", "height", "attrs"],
30
42
  additionalProperties: false,
31
43
  },
32
44
  },
@@ -50,8 +62,29 @@ function createPrompt(products, boxes, samples) {
50
62
  `🚨 LIMITES FÍSICOS OBRIGATÓRIOS:\n- Largura máxima: ${maxWidth}cm\n- Altura máxima: ${maxHeight}cm\n- Comprimento máximo: ${maxLength}cm\n(Maior caixa: ${box.name ?? "—"})\n\n` +
51
63
  `📦 PRODUTOS PARA ESTIMAR:\n${products.map((p, i) => `${i + 1}. ${p.name} - ${p.quantity}x (${p.weight}kg cada)`).join("\n")}\n` +
52
64
  samplesSection +
65
+ `\n🧱 COMO O PRODUTO OCUPA ESPAÇO (campo attrs, um por produto):\n` +
66
+ `- fragile: quebra se levar peso em cima — vidro, cerâmica, garrafa, ovo\n` +
67
+ `- compressible: cede quando espremido — roupa, tecido, espuma, travesseiro, pelúcia\n` +
68
+ `- nestable: unidades IGUAIS encaixam uma na outra — tigela, copo, cone, pote, vaso\n` +
69
+ `- keepUpright: precisa viajar em pé — líquido, tinta, bolo, planta\n` +
70
+ `Na dúvida responda false. Cada traço afrouxa o encaixe, e afrouxar errado faz o pacote não fechar.\n` +
53
71
  `\n⚠️ REGRAS: respeite os limites; preserve os nomes EXATOS; retorne length×width×height em cm.`);
54
72
  }
73
+ /**
74
+ * Só os traços verdadeiros, e nada quando não há nenhum.
75
+ *
76
+ * O schema obriga o modelo a responder os quatro booleanos, então quase todo
77
+ * produto volta com `{fragile:false, compressible:false, ...}`. Guardar isso é
78
+ * gravar ruído em cada linha da memória e, pior, apagar a diferença entre
79
+ * "sabemos que é um tijolo" e "não perguntamos" — que é justamente o que o
80
+ * empacotador precisa distinguir.
81
+ */
82
+ function attrsVerdadeiros(attrs) {
83
+ if (!attrs)
84
+ return null;
85
+ const so = Object.fromEntries(Object.entries(attrs).filter(([, v]) => v === true));
86
+ return Object.keys(so).length ? { attrs: so } : null;
87
+ }
55
88
  /** Apply the largest-box physical limits + a minimum-volume floor to AI output. */
56
89
  function validateAndOptimize(aiResult, products, boxes) {
57
90
  const box = largestBox(boxes);
@@ -80,6 +113,7 @@ function validateAndOptimize(aiResult, products, boxes) {
80
113
  length: Math.round(length * 10) / 10,
81
114
  width: Math.round(width * 10) / 10,
82
115
  height: Math.round(height * 10) / 10,
116
+ ...(attrsVerdadeiros(product.attrs) ?? {}),
83
117
  };
84
118
  });
85
119
  return { products: optimized };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meuecommerce/frete-adapter-node",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Node implementation of @meuecommerce/frete ports (Correios HTTP client) using global fetch. Used by the Shopify/Fly deployment and the MCP server.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@meuecommerce/frete": "^0.8.1"
34
+ "@meuecommerce/frete": "^0.9.0"
35
35
  },
36
36
  "module": "./dist/index.js",
37
37
  "repository": {