@meuecommerce/frete-adapter-node 0.3.1 → 0.4.1
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/dist/cjs/correiosHttpClient.js +31 -0
- package/dist/cjs/correiosLabelHttpClient.js +23 -1
- package/dist/cjs/inMemoryDimensionMemory.js +59 -0
- package/dist/cjs/index.js +11 -1
- package/dist/cjs/openAIDimensionEstimator.js +53 -63
- package/dist/cjs/openAIResponsesAgentRunner.js +119 -0
- package/dist/cjs/pgDimensionMemory.js +160 -0
- package/dist/correiosHttpClient.js +32 -1
- package/dist/correiosLabelHttpClient.js +23 -1
- package/dist/inMemoryDimensionMemory.d.ts +10 -0
- package/dist/inMemoryDimensionMemory.js +55 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +5 -1
- package/dist/openAIDimensionEstimator.d.ts +24 -4
- package/dist/openAIDimensionEstimator.js +52 -63
- package/dist/openAIResponsesAgentRunner.d.ts +50 -0
- package/dist/openAIResponsesAgentRunner.js +114 -0
- package/dist/pgDimensionMemory.d.ts +62 -0
- package/dist/pgDimensionMemory.js +157 -0
- package/package.json +6 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Postgres-backed `DimensionMemory` — the production counterpart of
|
|
3
|
+
* {@link InMemoryDimensionMemory}.
|
|
4
|
+
*
|
|
5
|
+
* Two rules from the port are enforced here in SQL rather than in application
|
|
6
|
+
* code, because the memory is written from more than one place (the quote path,
|
|
7
|
+
* the label feedback, the dashboard) and a check that lives in one caller is a
|
|
8
|
+
* check that the next caller forgets:
|
|
9
|
+
*
|
|
10
|
+
* - **A weaker layer never overwrites a stronger one.** The upsert carries the
|
|
11
|
+
* layer's rank and only updates when the incoming rank is at least as strong,
|
|
12
|
+
* so an agent estimate racing with a merchant's correction loses regardless of
|
|
13
|
+
* which arrives last.
|
|
14
|
+
* - **One round trip per cart.** `get` takes every product at once, because a
|
|
15
|
+
* query per line item is exactly what makes a hot path slow.
|
|
16
|
+
*
|
|
17
|
+
* The client is the structural {@link SqlClient} rather than a `pg` import, so
|
|
18
|
+
* this package gains no runtime dependency and the tests can run real SQL
|
|
19
|
+
* against pg-mem with no network.
|
|
20
|
+
*
|
|
21
|
+
* Lookups expand to `IN ($1, $2, …)` instead of the more idiomatic
|
|
22
|
+
* `= ANY($1)`. Real Postgres accepts both, but pg-mem silently returns zero
|
|
23
|
+
* rows for the array form, and running the tests against real SQL is worth more
|
|
24
|
+
* than the tidier query — a cart is a handful of line items, so the parameter
|
|
25
|
+
* count is not a concern. Revisit if this is ever used for bulk reads.
|
|
26
|
+
*/
|
|
27
|
+
import { MEMORY_LAYER_ORDER, canOverwrite, productKey } from "@meuecommerce/frete";
|
|
28
|
+
export const DIMENSION_MEMORY_SCHEMA_SQL = `
|
|
29
|
+
CREATE TABLE IF NOT EXISTS dimension_memory (
|
|
30
|
+
key TEXT PRIMARY KEY,
|
|
31
|
+
instance_id TEXT NOT NULL,
|
|
32
|
+
length_cm DOUBLE PRECISION NOT NULL,
|
|
33
|
+
width_cm DOUBLE PRECISION NOT NULL,
|
|
34
|
+
height_cm DOUBLE PRECISION NOT NULL,
|
|
35
|
+
attrs JSONB,
|
|
36
|
+
confidence DOUBLE PRECISION NOT NULL,
|
|
37
|
+
source TEXT NOT NULL,
|
|
38
|
+
layer_rank INTEGER NOT NULL,
|
|
39
|
+
prompt_version TEXT,
|
|
40
|
+
model TEXT,
|
|
41
|
+
updated_at TIMESTAMPTZ NOT NULL
|
|
42
|
+
);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS dimension_memory_instance_idx ON dimension_memory (instance_id);
|
|
44
|
+
`;
|
|
45
|
+
/** Lower rank = stronger layer, matching `MEMORY_LAYER_ORDER`. */
|
|
46
|
+
function layerRank(layer) {
|
|
47
|
+
const rank = MEMORY_LAYER_ORDER.indexOf(layer);
|
|
48
|
+
// Uma camada desconhecida é tratada como a mais fraca possível, em vez de
|
|
49
|
+
// virar -1 e passar por cima de tudo.
|
|
50
|
+
return rank === -1 ? MEMORY_LAYER_ORDER.length : rank;
|
|
51
|
+
}
|
|
52
|
+
/** `$1, $2, …` para `count` parâmetros. */
|
|
53
|
+
function placeholders(count) {
|
|
54
|
+
return Array.from({ length: count }, (_, i) => `$${i + 1}`).join(", ");
|
|
55
|
+
}
|
|
56
|
+
/** `DOUBLE PRECISION` chega como string em alguns drivers. */
|
|
57
|
+
function num(value) {
|
|
58
|
+
return typeof value === "number" ? value : Number(value);
|
|
59
|
+
}
|
|
60
|
+
function toRecord(row) {
|
|
61
|
+
const updatedAt = row.updated_at instanceof Date ? row.updated_at.toISOString() : String(row.updated_at);
|
|
62
|
+
return {
|
|
63
|
+
dims: { length: num(row.length_cm), width: num(row.width_cm), height: num(row.height_cm) },
|
|
64
|
+
...(row.attrs ? { attrs: row.attrs } : {}),
|
|
65
|
+
confidence: num(row.confidence),
|
|
66
|
+
source: row.source,
|
|
67
|
+
...(row.prompt_version ? { promptVersion: row.prompt_version } : {}),
|
|
68
|
+
...(row.model ? { model: row.model } : {}),
|
|
69
|
+
updatedAt,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export class PgDimensionMemory {
|
|
73
|
+
sql;
|
|
74
|
+
constructor(options) {
|
|
75
|
+
this.sql = options.sql;
|
|
76
|
+
}
|
|
77
|
+
/** Idempotent — safe to call on every boot. */
|
|
78
|
+
async migrate() {
|
|
79
|
+
await this.sql.query(DIMENSION_MEMORY_SCHEMA_SQL);
|
|
80
|
+
}
|
|
81
|
+
async get(identities) {
|
|
82
|
+
const keys = identities.flatMap((identity) => {
|
|
83
|
+
const key = productKey(identity);
|
|
84
|
+
return key ? [key.value] : [];
|
|
85
|
+
});
|
|
86
|
+
const found = new Map();
|
|
87
|
+
if (keys.length === 0)
|
|
88
|
+
return found;
|
|
89
|
+
const { rows } = await this.sql.query(`SELECT key, length_cm, width_cm, height_cm, attrs, confidence, source, prompt_version, model, updated_at
|
|
90
|
+
FROM dimension_memory
|
|
91
|
+
WHERE key IN (${placeholders(keys.length)})`, keys);
|
|
92
|
+
for (const row of rows)
|
|
93
|
+
found.set(row.key, toRecord(row));
|
|
94
|
+
return found;
|
|
95
|
+
}
|
|
96
|
+
async set(entries) {
|
|
97
|
+
const values = [];
|
|
98
|
+
const tuples = [];
|
|
99
|
+
for (const { identity, record } of entries) {
|
|
100
|
+
const key = productKey(identity);
|
|
101
|
+
// Sem chave derivável não há o que gravar: inventar uma faria produtos
|
|
102
|
+
// sem relação compartilharem entrada.
|
|
103
|
+
if (!key)
|
|
104
|
+
continue;
|
|
105
|
+
const base = values.length;
|
|
106
|
+
values.push(key.value, identity.instanceId, record.dims.length, record.dims.width, record.dims.height, record.attrs ? JSON.stringify(record.attrs) : null, record.confidence, record.source, layerRank(record.source), record.promptVersion ?? null, record.model ?? null, record.updatedAt);
|
|
107
|
+
const p = (offset) => `$${base + offset}`;
|
|
108
|
+
tuples.push(`(${p(1)}, ${p(2)}, ${p(3)}, ${p(4)}, ${p(5)}, ${p(6)}::jsonb, ${p(7)}, ${p(8)}, ${p(9)}, ${p(10)}, ${p(11)}, ${p(12)}::timestamptz)`);
|
|
109
|
+
}
|
|
110
|
+
if (tuples.length === 0)
|
|
111
|
+
return;
|
|
112
|
+
await this.sql.query(`INSERT INTO dimension_memory
|
|
113
|
+
(key, instance_id, length_cm, width_cm, height_cm, attrs, confidence, source, layer_rank, prompt_version, model, updated_at)
|
|
114
|
+
VALUES ${tuples.join(", ")}
|
|
115
|
+
ON CONFLICT (key) DO UPDATE SET
|
|
116
|
+
length_cm = EXCLUDED.length_cm,
|
|
117
|
+
width_cm = EXCLUDED.width_cm,
|
|
118
|
+
height_cm = EXCLUDED.height_cm,
|
|
119
|
+
attrs = EXCLUDED.attrs,
|
|
120
|
+
confidence = EXCLUDED.confidence,
|
|
121
|
+
source = EXCLUDED.source,
|
|
122
|
+
layer_rank = EXCLUDED.layer_rank,
|
|
123
|
+
prompt_version = EXCLUDED.prompt_version,
|
|
124
|
+
model = EXCLUDED.model,
|
|
125
|
+
updated_at = EXCLUDED.updated_at
|
|
126
|
+
WHERE EXCLUDED.layer_rank <= dimension_memory.layer_rank`, values);
|
|
127
|
+
}
|
|
128
|
+
async invalidate(identities) {
|
|
129
|
+
const keys = identities.flatMap((identity) => {
|
|
130
|
+
const key = productKey(identity);
|
|
131
|
+
return key ? [key.value] : [];
|
|
132
|
+
});
|
|
133
|
+
if (keys.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
await this.sql.query(`DELETE FROM dimension_memory WHERE key IN (${placeholders(keys.length)})`, keys);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Drop agent estimates produced by an older prompt.
|
|
139
|
+
*
|
|
140
|
+
* Only touches `L3`: what the merchant declared and what a real label proved
|
|
141
|
+
* do not go stale because we changed a prompt. Meant to run in background
|
|
142
|
+
* after a prompt bump — never on the quote path.
|
|
143
|
+
*/
|
|
144
|
+
async invalidateStaleEstimates(currentPromptVersion) {
|
|
145
|
+
const { rows } = await this.sql.query(`DELETE FROM dimension_memory
|
|
146
|
+
WHERE source = 'L3' AND (prompt_version IS NULL OR prompt_version <> $1)
|
|
147
|
+
RETURNING key`, [currentPromptVersion]);
|
|
148
|
+
return rows.length;
|
|
149
|
+
}
|
|
150
|
+
/** Forget everything for one merchant — uninstall, or a support reset. */
|
|
151
|
+
async forgetInstance(instanceId) {
|
|
152
|
+
const { rows } = await this.sql.query(`DELETE FROM dimension_memory WHERE instance_id = $1 RETURNING key`, [instanceId]);
|
|
153
|
+
return rows.length;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Re-exported so callers can reason about precedence without importing core. */
|
|
157
|
+
export { canOverwrite };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meuecommerce/frete-adapter-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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.
|
|
34
|
+
"@meuecommerce/frete": "^0.4.1"
|
|
35
35
|
},
|
|
36
36
|
"module": "./dist/index.js",
|
|
37
37
|
"repository": {
|
|
@@ -39,5 +39,8 @@
|
|
|
39
39
|
"url": "git+https://github.com/devstudio163/frete.git",
|
|
40
40
|
"directory": "packages/adapter-node"
|
|
41
41
|
},
|
|
42
|
-
"homepage": "https://github.com/devstudio163/frete"
|
|
42
|
+
"homepage": "https://github.com/devstudio163/frete",
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"pg-mem": "^3.0.14"
|
|
45
|
+
}
|
|
43
46
|
}
|