@agent-cards/commerce-sdk 0.9.0 → 0.11.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/README.md +142 -12
- package/dist/ack.d.ts +49 -2
- package/dist/ack.js +119 -6
- package/dist/adapters.d.ts +3 -3
- package/dist/adapters.js +1 -1
- package/dist/buy-tool.d.ts +201 -15
- package/dist/buy-tool.js +542 -108
- package/dist/client.d.ts +39 -3
- package/dist/client.js +66 -2
- package/dist/definition.js +16 -6
- package/dist/handler.d.ts +6 -0
- package/dist/handler.js +4 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/listen.d.ts +2 -0
- package/dist/listen.js +4 -1
- package/dist/message.d.ts +7 -2
- package/dist/messages.d.ts +33 -2
- package/dist/messages.js +82 -5
- package/dist/model-view.d.ts +28 -1
- package/dist/model-view.js +36 -5
- package/package.json +1 -1
package/dist/model-view.js
CHANGED
|
@@ -4,8 +4,14 @@ const MAX_PRODUCTS = 20;
|
|
|
4
4
|
const MARKDOWN_LINK = /\[([^\]]*)\]\([^)]*\)/g;
|
|
5
5
|
const SCHEME_URL = /\b[a-z][a-z0-9+.-]*:\/\/[^\s<>"'`)\]]*/gi;
|
|
6
6
|
const WWW_URL = /\bwww\.[^\s<>"'`)\]]*/gi;
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* A host followed by a path, a query or a fragment: `vault.agentcard.sh/a/1`, `vault.agentcard.sh?token=abc`. A `?` that
|
|
9
|
+
* only punctuation follows before a space, a closing bracket or quote, or the end starts no query: in "at glossier.com?
|
|
10
|
+
* Say yes" it is the question's mark, and the host reads as its site's name (BARE_HOST). A `?` that more of an address
|
|
11
|
+
* follows starts one, punctuation or not (`glossier.com?.ref=x`), and a `#` always starts a fragment
|
|
12
|
+
* (`glossier.com#:~:text=Balm`).
|
|
13
|
+
*/
|
|
14
|
+
const HOST_PATH = /\b(?:[a-z0-9-]+\.)+[a-z]{2,}(?:[/#]|\?(?![.,;:!?]*(?:[\s<>"'`)\]]|$)))[^\s<>"'`)\]]*/gi;
|
|
9
15
|
/**
|
|
10
16
|
* A bare host on a common top-level domain, such as `agentcard.sh` or `amazon.com`, which a chat app
|
|
11
17
|
* turns into a link. The list keeps words with a dot, such as `Node.js`, and an email address's host.
|
|
@@ -109,13 +115,35 @@ export function pickId(product) {
|
|
|
109
115
|
return product.ref;
|
|
110
116
|
return typeof product.id === 'string' && product.id !== '' && stripLinks(product.id) === product.id ? product.id : null;
|
|
111
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* What tells one product card from another: the product's link-free id, else its page. A restaurant gives
|
|
120
|
+
* every menu item the store's one page, so a card per page sent one card for a reply that offered three
|
|
121
|
+
* dishes (2026-10-20, Suavecito Birria & Tacos on DoorDash). Each product the model reads gets its own card.
|
|
122
|
+
*/
|
|
123
|
+
export function cardKey(product) {
|
|
124
|
+
return pickId(product) ?? (typeof product.url === 'string' && product.url !== '' ? product.url : null);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The key of the card a product gets, or null when it gets none: a product with a page at its store,
|
|
128
|
+
* or a flight option, which has no page, with an id a pick takes. A flight's card is how the shopper
|
|
129
|
+
* taps the flight they want (2026-10-20: three flights listed in text, and no card to tap).
|
|
130
|
+
*/
|
|
131
|
+
export function productCardKey(product) {
|
|
132
|
+
if (typeof product.url === 'string' && product.url !== '')
|
|
133
|
+
return cardKey(product);
|
|
134
|
+
return product.flight ? pickId(product) : null;
|
|
135
|
+
}
|
|
112
136
|
function cartView(cart) {
|
|
113
137
|
return {
|
|
114
138
|
store: stripLinks(cart.store?.name ?? cart.merchant_name) || stripLinks(cart.merchant),
|
|
115
139
|
items: cart.items.map((line) => ({ name: stripLinks(line.name), qty: line.qty, price: money(line.priceCents, cart.currency) })),
|
|
116
140
|
fees: cart.serviceFeesCents > 0 ? money(cart.serviceFeesCents, cart.currency) : null,
|
|
141
|
+
fee_lines: (cart.merchantFeeLines ?? []).map((line) => ({ label: stripLinks(line.label), amount: money(line.amountCents, cart.currency) })),
|
|
117
142
|
tip: cart.tipCents > 0 ? money(cart.tipCents, cart.currency) : null,
|
|
118
143
|
total: money(cart.totalCents, cart.currency) ?? money(0, cart.currency),
|
|
144
|
+
total_is_estimate: cart.totalIsEstimate === true,
|
|
145
|
+
// Agentcard names a ceiling equal to the total only for a hold of exactly the total, as a flight's.
|
|
146
|
+
max_charge: typeof cart.approvedCeilingCents === 'number' && cart.approvedCeilingCents > 0 && cart.approvedCeilingCents >= cart.totalCents ? money(cart.approvedCeilingCents, cart.currency) : null,
|
|
119
147
|
};
|
|
120
148
|
}
|
|
121
149
|
/**
|
|
@@ -127,7 +155,7 @@ function cartView(cart) {
|
|
|
127
155
|
export function forModel(result) {
|
|
128
156
|
const status = typeof result.status === 'string' && MODEL_STATUSES.has(result.status) ? result.status : 'needs_input';
|
|
129
157
|
const products = shownProducts(result.products);
|
|
130
|
-
const held = (product) => product.linkSent === true &&
|
|
158
|
+
const held = (product) => product.linkSent === true && productCardKey(product) !== null;
|
|
131
159
|
const stores = shownStores(result.stores);
|
|
132
160
|
const heldStore = (store) => store.linkSent === true && typeof store.url === 'string' && store.url !== '';
|
|
133
161
|
return {
|
|
@@ -141,8 +169,11 @@ export function forModel(result) {
|
|
|
141
169
|
shopper_need_not_reply: result.shopper_need_not_reply === true,
|
|
142
170
|
shopper_already_told_looking: result.shopper_already_told_looking === true,
|
|
143
171
|
link_sent: result.link_sent === true,
|
|
144
|
-
|
|
145
|
-
|
|
172
|
+
links_sent: result.link_sent === true
|
|
173
|
+
? [...new Set((result.links ?? []).map((link) => link.kind).filter((kind) => kind === 'vault' || kind === 'approval' || kind === 'store_login'))]
|
|
174
|
+
: [],
|
|
175
|
+
// A card per product, so two dishes on a restaurant's one page are two cards.
|
|
176
|
+
product_links_sent: new Set(products.filter(held).map(productCardKey)).size,
|
|
146
177
|
// The id the model sent, never the catalog id, which is a store page for a retail product.
|
|
147
178
|
pick: result.pick ? { product_id: pickId({ id: result.pick.product_id, ref: result.pick.ref }), in_cart: result.pick.in_cart === true } : null,
|
|
148
179
|
stores: stores.map((store) => ({ store_id: store.id, name: stripLinks(store.name), eta_minutes: store.etaMinutes, link_sent: heldStore(store) })),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/commerce-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Give your agent one tool that buys for your shoppers at real stores, and post each purchase update Agentcard sends into the shopper's chat, over a connection your server opens or a webhook endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|