@agent-cards/commerce-sdk 0.18.7 → 0.18.9
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/app-instructions.generated.d.ts +1 -1
- package/dist/app-instructions.generated.js +1 -1
- package/dist/buy-tool.d.ts +5 -0
- package/dist/buy-tool.js +2 -1
- package/dist/card-size.d.ts +22 -0
- package/dist/card-size.js +23 -0
- package/dist/client.d.ts +20 -0
- package/dist/client.js +20 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/model-view.d.ts +9 -1
- package/dist/model-view.js +11 -0
- package/dist/search-status.d.ts +11 -1
- package/dist/search-status.js +21 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The version of the voice package the text was copied from. */
|
|
2
|
-
export declare const VOICE_VERSION = "0.2.
|
|
2
|
+
export declare const VOICE_VERSION = "0.2.82";
|
|
3
3
|
export declare const APP_TEXT: {
|
|
4
4
|
readonly core: "You help a shopper buy what they ask for, with the `buy` tool from Agentcard.\n\nWhen the shopper asks what you can do, answer from these lines without calling the tool:\n- You buy from Amazon, Walmart, Target, Best Buy and thousands more stores. Say \"and thousands more stores\" every time you name the stores you shop, in a reply about one kind of thing too, such as \"travel gear from Amazon, Target and thousands more stores\". Never let a few names read as the whole list, never say \"most online stores\", \"plenty more\" or \"many more\", and never give a number of stores.\n- You plan a whole trip: the flights, a hotel and a rental car together. When they ask what you can do for travel, lead with the whole trip, then name the parts they can book on their own.\n- You order food delivery and book restaurant tables.\n\nHow you use the buy tool:\n- Call it for anything the shopper wants to find, buy, book or order, a trip with no dates or airport yet included: the tool asks for what it still needs.\n- Never say whether you can buy at a store the shopper names, either way. Only the tool knows, so say you will look and call it.\n- Never write a link. Each link reaches the shopper on its own, so when `link_sent` is true, tell them a link is waiting for them.\n- Tell the shopper no reply is needed only when `shopper_need_not_reply` is true.\n- Ask for one thing per message, the step `next_action` names, and leave every later step for a later message.\n- Never tell the shopper you can't show Markdown, a table or other formatting, and never say you keep to plain text.";
|
|
5
5
|
readonly markdown: "The app shows your words as Markdown. When the shopper asks for a table, a list or bold, write it in Markdown. Use a list or a table where it reads better than a sentence, and keep each message short all the same.";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GENERATED by scripts/app-instructions.mjs from apps/agent-voice/kb/app.md. Do not edit: edit kb/app.md.
|
|
2
2
|
/** The version of the voice package the text was copied from. */
|
|
3
|
-
export const VOICE_VERSION = "0.2.
|
|
3
|
+
export const VOICE_VERSION = "0.2.82";
|
|
4
4
|
export const APP_TEXT = {
|
|
5
5
|
"core": "You help a shopper buy what they ask for, with the `buy` tool from Agentcard.\n\nWhen the shopper asks what you can do, answer from these lines without calling the tool:\n- You buy from Amazon, Walmart, Target, Best Buy and thousands more stores. Say \"and thousands more stores\" every time you name the stores you shop, in a reply about one kind of thing too, such as \"travel gear from Amazon, Target and thousands more stores\". Never let a few names read as the whole list, never say \"most online stores\", \"plenty more\" or \"many more\", and never give a number of stores.\n- You plan a whole trip: the flights, a hotel and a rental car together. When they ask what you can do for travel, lead with the whole trip, then name the parts they can book on their own.\n- You order food delivery and book restaurant tables.\n\nHow you use the buy tool:\n- Call it for anything the shopper wants to find, buy, book or order, a trip with no dates or airport yet included: the tool asks for what it still needs.\n- Never say whether you can buy at a store the shopper names, either way. Only the tool knows, so say you will look and call it.\n- Never write a link. Each link reaches the shopper on its own, so when `link_sent` is true, tell them a link is waiting for them.\n- Tell the shopper no reply is needed only when `shopper_need_not_reply` is true.\n- Ask for one thing per message, the step `next_action` names, and leave every later step for a later message.\n- Never tell the shopper you can't show Markdown, a table or other formatting, and never say you keep to plain text.",
|
|
6
6
|
"markdown": "The app shows your words as Markdown. When the shopper asks for a table, a list or bold, write it in Markdown. Use a list or a table where it reads better than a sentence, and keep each message short all the same.",
|
package/dist/buy-tool.d.ts
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* messages and links as one sequence, in the order they happened, and spaces
|
|
32
32
|
* the messages like someone texting.
|
|
33
33
|
*/
|
|
34
|
+
import type { BuyCardSize } from './card-size.js';
|
|
34
35
|
import type { BuyPlan } from './plan.js';
|
|
35
36
|
import type { BuyMerchantStatusUpdate, BuySearchStatus } from './search-status.js';
|
|
36
37
|
import type { BuyFulfilledBy } from './fulfilled-by.js';
|
|
@@ -97,6 +98,8 @@ export interface BuyToolLink {
|
|
|
97
98
|
* `{ name: 'StubHub', kind: 'marketplace', line: 'via StubHub' }`. Show `line` quietly under the price. Absent when none.
|
|
98
99
|
*/
|
|
99
100
|
fulfilledBy?: BuyFulfilledBy;
|
|
101
|
+
/** On a product link: the shopper's size as the store's read found it. Show `line` under the price when it is not null. */
|
|
102
|
+
shopperSize?: BuyCardSize;
|
|
100
103
|
/**
|
|
101
104
|
* On a product link: what taking the product does, so a button can say it. `reserve` is a table the
|
|
102
105
|
* shopper reserves, `book` a flight, room, class or ticket they book, and `buy` anything they buy.
|
|
@@ -186,6 +189,8 @@ export interface BuyToolProduct {
|
|
|
186
189
|
availability?: BuyAvailability;
|
|
187
190
|
/** Who sells or books it, where that is not the store it names (`via StubHub`); absent when Agentcard named none. */
|
|
188
191
|
fulfilledBy?: BuyFulfilledBy;
|
|
192
|
+
/** The shopper's size as the store's read found it (`men's 10.5 in stock`); absent when none was asked or read. */
|
|
193
|
+
shopperSize?: BuyCardSize;
|
|
189
194
|
}
|
|
190
195
|
/** One answer of the buy tool, whole, for your code. Hand it to `forModel` before a model reads it. */
|
|
191
196
|
export interface BuyToolResult {
|
package/dist/buy-tool.js
CHANGED
|
@@ -242,7 +242,7 @@ export function productsOf(turn) {
|
|
|
242
242
|
/** A product's card as `sendLink` hears it: the id the model reads and a pick takes, never the store page, which is `url`. A flight option has no page at a store: its card carries no url, and its productId picks it. */
|
|
243
243
|
function productLink(product) {
|
|
244
244
|
const productId = pickId(product);
|
|
245
|
-
return { kind: 'product', url: product.url || null, title: product.name, price: productPrice(product), ...(productId ? { productId } : {}), action: product.action ?? 'buy', imageUrl: product.imageUrl, images: product.images ?? (product.imageUrl ? [product.imageUrl] : []), store: product.store ?? null, storeDomain: product.storeDomain ?? null, expiresAt: null, ...(product.availability ? { availability: product.availability } : {}), ...(product.fulfilledBy ? { fulfilledBy: product.fulfilledBy } : {}) };
|
|
245
|
+
return { kind: 'product', url: product.url || null, title: product.name, price: productPrice(product), ...(productId ? { productId } : {}), action: product.action ?? 'buy', imageUrl: product.imageUrl, images: product.images ?? (product.imageUrl ? [product.imageUrl] : []), store: product.store ?? null, storeDomain: product.storeDomain ?? null, expiresAt: null, ...(product.availability ? { availability: product.availability } : {}), ...(product.fulfilledBy ? { fulfilledBy: product.fulfilledBy } : {}), ...(product.shopperSize ? { shopperSize: product.shopperSize } : {}) };
|
|
246
246
|
}
|
|
247
247
|
/** A host name: dot-separated labels of letters, digits and hyphens, ending in a letters-only top-level label. */
|
|
248
248
|
const STORE_HOST = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/;
|
|
@@ -279,6 +279,7 @@ function productsOfCatalog(catalog) {
|
|
|
279
279
|
linkSent: false,
|
|
280
280
|
...(item.availability ? { availability: item.availability } : {}),
|
|
281
281
|
...(item.fulfilled_by ? { fulfilledBy: item.fulfilled_by } : {}),
|
|
282
|
+
...(item.shopper_size ? { shopperSize: item.shopper_size } : {}),
|
|
282
283
|
}));
|
|
283
284
|
}
|
|
284
285
|
/** The stores an answer presents, as the tool reads them. */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shopper's size on a product card, as Agentcard sends it on a shoe or a garment it read at the store for the size the
|
|
3
|
+
* shopper named: the size asked for, the store's own label for it, and whether the store has it in stock. `available` is
|
|
4
|
+
* null when no read answered, and the card then says nothing of the size: an app never shows a size as in stock that
|
|
5
|
+
* Agentcard did not read. `line` is the words to show under the price, or null when there is nothing to say.
|
|
6
|
+
*/
|
|
7
|
+
export interface BuyCardSize {
|
|
8
|
+
/** The size the shopper asked for, as they read it: `men's 10.5`, `EU 44`, `size M`. */
|
|
9
|
+
requested: string;
|
|
10
|
+
/** The store's own label for that size (`10.5`, `M 10 / W 11.5`), or null when the store does not sell it. */
|
|
11
|
+
label: string | null;
|
|
12
|
+
/** True when the store has it in stock, false when it does not sell it or sold out of it, null when unread. */
|
|
13
|
+
available: boolean | null;
|
|
14
|
+
/** `men's 10.5 in stock` or `No men's 10.5 here`; null when `available` is null. */
|
|
15
|
+
line: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** `shopper_size` as Agentcard sent it, or null when it sent none or a shape this version cannot read. */
|
|
18
|
+
export declare function cardSizeOf(v: unknown): BuyCardSize | null;
|
|
19
|
+
/** `{ shopper_size }` when Agentcard sent one, else nothing: a card with no size carries no field. */
|
|
20
|
+
export declare function cardSizeField(v: Record<string, unknown>): {
|
|
21
|
+
shopper_size?: BuyCardSize;
|
|
22
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shopper's size on a product card, as Agentcard sends it on a shoe or a garment it read at the store for the size the
|
|
3
|
+
* shopper named: the size asked for, the store's own label for it, and whether the store has it in stock. `available` is
|
|
4
|
+
* null when no read answered, and the card then says nothing of the size: an app never shows a size as in stock that
|
|
5
|
+
* Agentcard did not read. `line` is the words to show under the price, or null when there is nothing to say.
|
|
6
|
+
*/
|
|
7
|
+
/** `shopper_size` as Agentcard sent it, or null when it sent none or a shape this version cannot read. */
|
|
8
|
+
export function cardSizeOf(v) {
|
|
9
|
+
if (!v || typeof v !== 'object')
|
|
10
|
+
return null;
|
|
11
|
+
const r = v;
|
|
12
|
+
if (typeof r.requested !== 'string' || !r.requested.trim())
|
|
13
|
+
return null;
|
|
14
|
+
const available = r.available === true ? true : r.available === false ? false : null;
|
|
15
|
+
const label = typeof r.label === 'string' && r.label.trim() ? r.label : null;
|
|
16
|
+
const line = available === true ? `${r.requested} in stock` : available === false ? `No ${r.requested} here` : null;
|
|
17
|
+
return { requested: r.requested, label, available, line };
|
|
18
|
+
}
|
|
19
|
+
/** `{ shopper_size }` when Agentcard sent one, else nothing: a card with no size carries no field. */
|
|
20
|
+
export function cardSizeField(v) {
|
|
21
|
+
const size = cardSizeOf(v.shopper_size);
|
|
22
|
+
return size ? { shopper_size: size } : {};
|
|
23
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { type BuyPlan } from './plan.js';
|
|
12
12
|
import { type BuyMerchantStatusUpdate, type BuySearchStatus } from './search-status.js';
|
|
13
13
|
import { type BuyFulfilledBy } from './fulfilled-by.js';
|
|
14
|
+
import { type BuyCardSize } from './card-size.js';
|
|
14
15
|
import { type AgentcardListener, type ListenOptions } from './listen.js';
|
|
15
16
|
import { type ShopperMessage } from './shopper-message.js';
|
|
16
17
|
/** The fetch the client calls: Node 18 and later have one built in. */
|
|
@@ -109,6 +110,11 @@ export interface BuyTurnStatus {
|
|
|
109
110
|
step: string;
|
|
110
111
|
text: string;
|
|
111
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* The words this SDK shows for a step whatever Agentcard's own line says, so every app reads the same line. `searching_wider`
|
|
115
|
+
* comes when a search across every store has shown no product for a while and keeps running; its products still come as cards.
|
|
116
|
+
*/
|
|
117
|
+
export declare const STATUS_WORDING: Readonly<Record<string, string>>;
|
|
112
118
|
/** One message Agentcard finished writing while the turn runs, links included, as the answer's `messages` then holds it. */
|
|
113
119
|
export interface BuySegmentUpdate {
|
|
114
120
|
conversationId: string | null;
|
|
@@ -424,6 +430,18 @@ export interface BuyFlightItinerary {
|
|
|
424
430
|
arrivalAt: string | null;
|
|
425
431
|
cabinClasses: Array<string | null>;
|
|
426
432
|
}>;
|
|
433
|
+
/** Who the price covers, when it covers more than one passenger: `priceCents` is then the whole party's. Absent for one passenger and from an older API. */
|
|
434
|
+
party?: BuyFlightParty;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* A flight price for a party. `totalCents` is the price for every passenger together, the same as the card's `priceCents`.
|
|
438
|
+
* `perPassengerCents` is each passenger's share, adults first, when Agentcard knows it; absent when the fares differ by age.
|
|
439
|
+
*/
|
|
440
|
+
export interface BuyFlightParty {
|
|
441
|
+
adults: number;
|
|
442
|
+
children: number;
|
|
443
|
+
totalCents: number;
|
|
444
|
+
perPassengerCents?: number[];
|
|
427
445
|
}
|
|
428
446
|
export interface BuyCatalogItem {
|
|
429
447
|
flight?: BuyFlightItinerary;
|
|
@@ -449,6 +467,8 @@ export interface BuyCatalogItem {
|
|
|
449
467
|
availability?: BuyAvailability;
|
|
450
468
|
/** Who sells or books the product, where that is not the store the card names (`booked with OpenTable`); absent when Agentcard named none. */
|
|
451
469
|
fulfilled_by?: BuyFulfilledBy;
|
|
470
|
+
/** The size the shopper named, as the store's read of this product found it (BuyCardSize); absent when none was asked or read. */
|
|
471
|
+
shopper_size?: BuyCardSize;
|
|
452
472
|
}
|
|
453
473
|
/**
|
|
454
474
|
* The products the last search found. `presented` is true when this answer's reply presents them: the
|
package/dist/client.js
CHANGED
|
@@ -12,8 +12,16 @@ import { planOf } from './plan.js';
|
|
|
12
12
|
import { merchantStatusOf, searchOf } from './search-status.js';
|
|
13
13
|
import { isRecord } from './verify.js';
|
|
14
14
|
import { failedPartyOf, fulfilledByField } from './fulfilled-by.js';
|
|
15
|
+
import { cardSizeField } from './card-size.js';
|
|
15
16
|
import { listenToAgentcard } from './listen.js';
|
|
16
17
|
import { messageInChat } from './shopper-message.js';
|
|
18
|
+
/**
|
|
19
|
+
* The words this SDK shows for a step whatever Agentcard's own line says, so every app reads the same line. `searching_wider`
|
|
20
|
+
* comes when a search across every store has shown no product for a while and keeps running; its products still come as cards.
|
|
21
|
+
*/
|
|
22
|
+
export const STATUS_WORDING = Object.freeze({
|
|
23
|
+
searching_wider: 'Checking more stores for this…',
|
|
24
|
+
});
|
|
17
25
|
/** The handlers that ask Agentcard to stream a turn. */
|
|
18
26
|
const STREAM_HANDLERS = ['onProgress', 'onStatus', 'onFound', 'onCatalog', 'onSegment', 'onAck', 'onCart', 'onDelta', 'onAvailability', 'onReplyWritten', 'onMerchantStatus'];
|
|
19
27
|
const PROGRESS_STAGES = new Set(['searching', 'building_cart', 'checking_out', 'working']);
|
|
@@ -233,8 +241,18 @@ function flightOf(value) {
|
|
|
233
241
|
departureAt: str(leg.departureAt), arrivalAt: str(leg.arrivalAt),
|
|
234
242
|
cabinClasses: Array.isArray(leg.cabinClasses) ? leg.cabinClasses.map(str) : [] };
|
|
235
243
|
}),
|
|
244
|
+
...partyOf(value.party),
|
|
236
245
|
};
|
|
237
246
|
}
|
|
247
|
+
function partyOf(value) {
|
|
248
|
+
if (!isRecord(value))
|
|
249
|
+
return {};
|
|
250
|
+
const adults = num(value.adults), children = num(value.children), totalCents = num(value.totalCents);
|
|
251
|
+
if (adults === null || children === null || totalCents === null || adults + children < 2)
|
|
252
|
+
return {};
|
|
253
|
+
const each = Array.isArray(value.perPassengerCents) ? value.perPassengerCents.map(num) : null;
|
|
254
|
+
return { party: { adults, children, totalCents, ...(each && each.length === adults + children && each.every((c) => c !== null) ? { perPassengerCents: each } : {}) } };
|
|
255
|
+
}
|
|
238
256
|
function catalogOf(v) {
|
|
239
257
|
if (!isRecord(v))
|
|
240
258
|
return null;
|
|
@@ -259,6 +277,7 @@ function catalogItemsOf(v) {
|
|
|
259
277
|
url: pageUrl(i.url),
|
|
260
278
|
...availabilityField(i),
|
|
261
279
|
...fulfilledByField(i),
|
|
280
|
+
...cardSizeField(i),
|
|
262
281
|
};
|
|
263
282
|
}) : [];
|
|
264
283
|
}
|
|
@@ -554,7 +573,7 @@ async function readStreamedTurn(res, stream, timeoutMs) {
|
|
|
554
573
|
}
|
|
555
574
|
else if (event === 'status' && typeof data.text === 'string' && data.text.trim() !== '' && typeof data.step === 'string' && stream.onStatus) {
|
|
556
575
|
try {
|
|
557
|
-
stream.onStatus({ conversationId: named, step: data.step, text: data.text });
|
|
576
|
+
stream.onStatus({ conversationId: named, step: data.step, text: Object.hasOwn(STATUS_WORDING, data.step) ? STATUS_WORDING[data.step] : data.text });
|
|
558
577
|
}
|
|
559
578
|
catch {
|
|
560
579
|
// The app's display failing never fails the turn.
|
package/dist/index.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ export { readPurchaseMessage, type PurchaseMessage, type PurchaseMessageKind, ty
|
|
|
3
3
|
export { readShopperMessage, isStale, SHOPPER_EVENT_TYPES, NEXT_STEP_KINDS, type NextStepKind, type ShopperMessage, type ShopperMessageKind, type ShopperFacts, type ShopperEventType, type OrderStatus, } from './shopper-message.js';
|
|
4
4
|
export { ORDER_STEPS, updateOrder, arrivalText, type ShopperOrder, type OrderStep, type OrderPathStep, type OrderStepState, type ArrivalTextOptions, } from './order.js';
|
|
5
5
|
export { agentcardWebhook, purchaseAgentWebhook, type AgentcardWebhookOptions, type AgentcardWebhookHandler, type PurchaseAgentWebhookOptions, type WebhookFetchRequest, type WebhookRequest, type WebhookResponse, } from './handler.js';
|
|
6
|
-
export { searchAt, isMerchantStatusAt, type BuySearchStatus, type BuyMerchantStatus, type BuyMerchantSearchStatus, type BuyMerchantStatusUpdate, } from './search-status.js';
|
|
7
|
-
export { AgentcardClient, AgentcardApiError, BUY_TURN_TIMEOUT_MS, DEFAULT_BASE_URL, type AgentcardClientOptions, type AgentcardTraceOptions, type OtelApi, type TraceContext, type FetchLike, type FetchLikeResponse, type BuyProgress, type BuyProgressStage, type BuyCatalogUpdate, type BuyAvailability, type BuyAvailabilityUpdate, type BuyFoundUpdate, type BuyTurnStatus, type BuySegmentUpdate, type BuyCartUpdate, type BuyDeltaUpdate, type BuyStreamHandlers, type Shopper, type BuyLastAnswer, type BuyRequest, type BuyDeliveryAddress, type BuyTurn, type BuyStatus, type BuyCart, type BuyCartBuilding, type BuyCartLine, type BuyCartFeeLine, type BuyCartDiscount, type BuyCartHold, type BuyStore, type BuyCatalog, type BuyCatalogItem, type BuyFlightItinerary, type BuyPaymentSource, type BuyConversation, type BuyLatestReply, type BuyLastCheckout, type BuyOrder, type VaultLink, type BuyNextAction, type BuyPick, type BuyStoreChoice, type BuyStorePick, type BuyStores, type BuyChoice, type BuyCodeRequest, type BuyChoiceGroup, type BuyChoiceDelivery, type BuyChoiceOption, } from './client.js';
|
|
6
|
+
export { searchAt, isMerchantStatusAt, merchantStatusLine, searchStatusLines, type BuySearchStatus, type BuyMerchantStatus, type BuyMerchantSearchStatus, type BuyMerchantStatusUpdate, } from './search-status.js';
|
|
7
|
+
export { AgentcardClient, AgentcardApiError, BUY_TURN_TIMEOUT_MS, DEFAULT_BASE_URL, type AgentcardClientOptions, type AgentcardTraceOptions, type OtelApi, type TraceContext, type FetchLike, type FetchLikeResponse, type BuyProgress, type BuyProgressStage, type BuyCatalogUpdate, type BuyAvailability, type BuyAvailabilityUpdate, type BuyFoundUpdate, type BuyTurnStatus, STATUS_WORDING, type BuySegmentUpdate, type BuyCartUpdate, type BuyDeltaUpdate, type BuyStreamHandlers, type Shopper, type BuyLastAnswer, type BuyRequest, type BuyDeliveryAddress, type BuyTurn, type BuyStatus, type BuyCart, type BuyCartBuilding, type BuyCartLine, type BuyCartFeeLine, type BuyCartDiscount, type BuyCartHold, type BuyStore, type BuyCatalog, type BuyCatalogItem, type BuyFlightItinerary, type BuyFlightParty, type BuyPaymentSource, type BuyConversation, type BuyLatestReply, type BuyLastCheckout, type BuyOrder, type VaultLink, type BuyNextAction, type BuyPick, type BuyStoreChoice, type BuyStorePick, type BuyStores, type BuyChoice, type BuyCodeRequest, type BuyChoiceGroup, type BuyChoiceDelivery, type BuyChoiceOption, } from './client.js';
|
|
8
8
|
export { BUY_TOOL_NAME, BUY_TOOL_DESCRIPTION, buyToolDefinition, parseBuyToolInput, type BuyToolDefinition, type BuyToolInput, type BuyToolInputSchema, type BuyToolInputCheck, type BuyToolStandardSchema, type OpenAIBuyTool, } from './definition.js';
|
|
9
9
|
export { toMessages, messageStream, typingDelay, type MessagePace, type MessageStream, type MessageStreamOptions, } from './messages.js';
|
|
10
10
|
export { buyTool, nextStepPrompt, type BuyTool, type BuyToolOptions, type BuyToolResult, type BuyToolStatus, type BuyToolLink, type BuyToolFound, type BuyToolAvailability, type BuyToolProduct, type BuyToolProductAction, productAction, type BuyToolStore, type BuyToolTurn, type BuyToolTurnItem, type BuyToolTurnOptions, type BuyToolTurnMessage, type BuyAckMode, } from './buy-tool.js';
|
|
11
11
|
export { instantAck, instantReaction, ackFor, keepsYes, ACK_REACTION, type AckForOptions } from './ack.js';
|
|
12
12
|
export { directCall, isProductAsk, type DirectCall, type DirectContext, type DirectReason } from './direct.js';
|
|
13
|
-
export { forModel, grandTotals, forModelError, stepAsWritten, withoutCardList, stripLinks, type BuyToolModelView, type BuyToolModelCart, type BuyToolGrandTotal, type BuyToolModelProduct, type BuyToolModelStore, type ShownCard, } from './model-view.js';
|
|
13
|
+
export { forModel, grandTotals, forModelError, stepAsWritten, withoutCardList, stripLinks, flightPartyWords, type BuyToolModelView, type BuyToolModelCart, type BuyToolGrandTotal, type BuyToolModelProduct, type BuyToolModelStore, type ShownCard, } from './model-view.js';
|
|
14
14
|
export { asBullets, choiceLines, replyAsWritten, textingStyle, withChoice, type ReplyAsWrittenOptions } from './texting.js';
|
|
15
15
|
export { appInstructions, APP_INSTRUCTIONS_VERSION, type AppInstructionsOptions } from './app-instructions.js';
|
|
16
16
|
export { toAnthropicTool, toOpenRouterTool, type AnthropicBuyTool, type OpenRouterToolkit, type ZodLike, } from './adapters.js';
|
|
@@ -22,3 +22,4 @@ export { TURN_RECOVERY_ON, isTurnId, type TurnEvent, type TurnRecord, type TurnR
|
|
|
22
22
|
export type { BuyLateResults, BuyStoreWait } from './store-wait.js';
|
|
23
23
|
export { planOf, type BuyPlan, type BuyPlanItem, type BuyPlanItemState, type BuyPlanStatus } from './plan.js';
|
|
24
24
|
export { fulfilledByLine, fulfilledByOf, type BuyFulfilledBy, type BuyFulfilledByKind } from './fulfilled-by.js';
|
|
25
|
+
export { cardSizeOf, type BuyCardSize } from './card-size.js';
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ export { readPurchaseMessage, } from './message.js';
|
|
|
3
3
|
export { readShopperMessage, isStale, SHOPPER_EVENT_TYPES, NEXT_STEP_KINDS, } from './shopper-message.js';
|
|
4
4
|
export { ORDER_STEPS, updateOrder, arrivalText, } from './order.js';
|
|
5
5
|
export { agentcardWebhook, purchaseAgentWebhook, } from './handler.js';
|
|
6
|
-
export { searchAt, isMerchantStatusAt, } from './search-status.js';
|
|
7
|
-
export { AgentcardClient, AgentcardApiError, BUY_TURN_TIMEOUT_MS, DEFAULT_BASE_URL, } from './client.js';
|
|
6
|
+
export { searchAt, isMerchantStatusAt, merchantStatusLine, searchStatusLines, } from './search-status.js';
|
|
7
|
+
export { AgentcardClient, AgentcardApiError, BUY_TURN_TIMEOUT_MS, DEFAULT_BASE_URL, STATUS_WORDING, } from './client.js';
|
|
8
8
|
export { BUY_TOOL_NAME, BUY_TOOL_DESCRIPTION, buyToolDefinition, parseBuyToolInput, } from './definition.js';
|
|
9
9
|
export { toMessages, messageStream, typingDelay, } from './messages.js';
|
|
10
10
|
export { buyTool, nextStepPrompt, productAction, } from './buy-tool.js';
|
|
11
11
|
export { instantAck, instantReaction, ackFor, keepsYes, ACK_REACTION } from './ack.js';
|
|
12
12
|
export { directCall, isProductAsk } from './direct.js';
|
|
13
|
-
export { forModel, grandTotals, forModelError, stepAsWritten, withoutCardList, stripLinks, } from './model-view.js';
|
|
13
|
+
export { forModel, grandTotals, forModelError, stepAsWritten, withoutCardList, stripLinks, flightPartyWords, } from './model-view.js';
|
|
14
14
|
export { asBullets, choiceLines, replyAsWritten, textingStyle, withChoice } from './texting.js';
|
|
15
15
|
export { appInstructions, APP_INSTRUCTIONS_VERSION } from './app-instructions.js';
|
|
16
16
|
export { toAnthropicTool, toOpenRouterTool, } from './adapters.js';
|
|
@@ -21,3 +21,4 @@ export { turnStream, readTurn, TURN_RECORD_TTL_SECONDS } from './turn-stream.js'
|
|
|
21
21
|
export { TURN_RECOVERY_ON, isTurnId } from './turn-record.js';
|
|
22
22
|
export { planOf } from './plan.js';
|
|
23
23
|
export { fulfilledByLine, fulfilledByOf } from './fulfilled-by.js';
|
|
24
|
+
export { cardSizeOf } from './card-size.js';
|
package/dist/model-view.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `product_links_sent` for the products' store pages, and `link_sent` on each
|
|
8
8
|
* store and `store_links_sent` for the pages of the stores to pick from.
|
|
9
9
|
*/
|
|
10
|
-
import type { BuyCart, BuyNextAction } from './client.js';
|
|
10
|
+
import type { BuyCart, BuyFlightParty, BuyNextAction } from './client.js';
|
|
11
11
|
import type { BuyToolProduct, BuyToolResult, BuyToolStatus, BuyToolStore } from './buy-tool.js';
|
|
12
12
|
export interface BuyToolModelCart {
|
|
13
13
|
store: string;
|
|
@@ -208,7 +208,15 @@ export declare function productPrice(product: {
|
|
|
208
208
|
priceCents: number | null;
|
|
209
209
|
currency: string | null;
|
|
210
210
|
priceFrom?: true;
|
|
211
|
+
flight?: {
|
|
212
|
+
party?: BuyFlightParty;
|
|
213
|
+
};
|
|
211
214
|
}): string | null;
|
|
215
|
+
/**
|
|
216
|
+
* Who a party's flight price covers, as every app shows it after the price: `for 2`, or `for 2 adults and 1 child` when
|
|
217
|
+
* children fly. `$1,610 for 2` is the price of both seats together.
|
|
218
|
+
*/
|
|
219
|
+
export declare function flightPartyWords(party: BuyFlightParty): string;
|
|
212
220
|
export declare function money(minor: number | null | undefined, currency: string | null | undefined): string | null;
|
|
213
221
|
/**
|
|
214
222
|
* The products the model reads: the first twenty that keep a name and a store
|
package/dist/model-view.js
CHANGED
|
@@ -110,8 +110,19 @@ function currencyFormat(currency) {
|
|
|
110
110
|
*/
|
|
111
111
|
export function productPrice(product) {
|
|
112
112
|
const price = money(product.priceCents, product.currency);
|
|
113
|
+
if (price !== null && product.flight?.party)
|
|
114
|
+
return `${price} ${flightPartyWords(product.flight.party)}`;
|
|
113
115
|
return price !== null && product.priceFrom ? `from ${price}` : price;
|
|
114
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Who a party's flight price covers, as every app shows it after the price: `for 2`, or `for 2 adults and 1 child` when
|
|
119
|
+
* children fly. `$1,610 for 2` is the price of both seats together.
|
|
120
|
+
*/
|
|
121
|
+
export function flightPartyWords(party) {
|
|
122
|
+
if (party.children === 0)
|
|
123
|
+
return `for ${party.adults}`;
|
|
124
|
+
return `for ${party.adults} adult${party.adults === 1 ? '' : 's'} and ${party.children} ${party.children === 1 ? 'child' : 'children'}`;
|
|
125
|
+
}
|
|
115
126
|
export function money(minor, currency) {
|
|
116
127
|
if (typeof minor !== 'number' || !Number.isFinite(minor))
|
|
117
128
|
return null;
|
package/dist/search-status.d.ts
CHANGED
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
* - `no_results`: the store answered, with nothing for the ask.
|
|
13
13
|
* - `timed_out`: the search answered without the store, which was still running.
|
|
14
14
|
* - `failed`: the store's search failed.
|
|
15
|
+
* - `unavailable`: Agentcard could not reach the store this turn. Show it only for a store the shopper named, with
|
|
16
|
+
* `merchantStatusLine`, and leave a store they did not name out.
|
|
15
17
|
*/
|
|
16
|
-
export type BuyMerchantSearchStatus = 'searching' | 'confirmed' | 'recently_confirmed' | 'no_results' | 'timed_out' | 'confirmation_unavailable' | 'failed';
|
|
18
|
+
export type BuyMerchantSearchStatus = 'searching' | 'confirmed' | 'recently_confirmed' | 'no_results' | 'timed_out' | 'confirmation_unavailable' | 'failed' | 'unavailable';
|
|
17
19
|
/** One store in the answer's `search` block, as Agentcard sends it. */
|
|
18
20
|
export interface BuyMerchantStatus {
|
|
19
21
|
/** The store's id: a store Agentcard knows by name, such as `walmart`, or the store's domain, such as `livlyclothing.com`. */
|
|
@@ -70,3 +72,11 @@ export declare function merchantStatusOf(data: Record<string, unknown>): BuyMerc
|
|
|
70
72
|
export declare function searchAt(search: BuySearchStatus | null, store: string): BuySearchStatus | null;
|
|
71
73
|
/** Whether a `merchant` event is about the store you name, as `searchAt` matches it. */
|
|
72
74
|
export declare function isMerchantStatusAt(update: BuyMerchantStatusUpdate, store: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The line to show the shopper for one store's status, or null for none. A store the shopper named (`named`, by its domain, id
|
|
77
|
+
* or name) that reads `unavailable` reads `still loading Walmart`; every other store and status reads nothing, so a store
|
|
78
|
+
* the shopper did not name drops out quietly while other stores fill the answer.
|
|
79
|
+
*/
|
|
80
|
+
export declare function merchantStatusLine(store: BuyMerchantStatus | BuyMerchantStatusUpdate, named: string | readonly string[]): string | null;
|
|
81
|
+
/** Every line `merchantStatusLine` gives for the turn's stores, in the order their searches started; none when `search` is null. */
|
|
82
|
+
export declare function searchStatusLines(search: BuySearchStatus | null, named: string | readonly string[]): string[];
|
package/dist/search-status.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Where each store a turn searches stands: the `merchant` events of a streamed turn, one each time a store's status changes, and
|
|
3
3
|
* the `search` block of the answer, every store at once.
|
|
4
4
|
*/
|
|
5
|
-
const MERCHANT_STATUSES = new Set(['searching', 'confirmed', 'recently_confirmed', 'no_results', 'timed_out', 'confirmation_unavailable', 'failed']);
|
|
5
|
+
const MERCHANT_STATUSES = new Set(['searching', 'confirmed', 'recently_confirmed', 'no_results', 'timed_out', 'confirmation_unavailable', 'failed', 'unavailable']);
|
|
6
6
|
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
7
7
|
const text = (v) => (typeof v === 'string' && v !== '' ? v : null);
|
|
8
8
|
const count = (v) => (typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.round(v) : 0);
|
|
@@ -76,3 +76,23 @@ export function isMerchantStatusAt(update, store) {
|
|
|
76
76
|
const want = storeKey(store);
|
|
77
77
|
return storeKey(update.merchant) === want || storeKey(update.merchantName) === want;
|
|
78
78
|
}
|
|
79
|
+
/** Whether a store, as a line or an update carries it, is one of the stores you name, as `searchAt` matches them. */
|
|
80
|
+
function isNamed(store, named) {
|
|
81
|
+
const name = 'merchant_name' in store ? store.merchant_name : store.merchantName;
|
|
82
|
+
const keys = new Set([storeKey(store.merchant), storeKey(name)]);
|
|
83
|
+
return (typeof named === 'string' ? [named] : named).some((n) => keys.has(storeKey(n)));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The line to show the shopper for one store's status, or null for none. A store the shopper named (`named`, by its domain, id
|
|
87
|
+
* or name) that reads `unavailable` reads `still loading Walmart`; every other store and status reads nothing, so a store
|
|
88
|
+
* the shopper did not name drops out quietly while other stores fill the answer.
|
|
89
|
+
*/
|
|
90
|
+
export function merchantStatusLine(store, named) {
|
|
91
|
+
if (store.status !== 'unavailable' || !isNamed(store, named))
|
|
92
|
+
return null;
|
|
93
|
+
return `still loading ${'merchant_name' in store ? store.merchant_name : store.merchantName}`;
|
|
94
|
+
}
|
|
95
|
+
/** Every line `merchantStatusLine` gives for the turn's stores, in the order their searches started; none when `search` is null. */
|
|
96
|
+
export function searchStatusLines(search, named) {
|
|
97
|
+
return (search?.merchants ?? []).flatMap((m) => merchantStatusLine(m, named) ?? []);
|
|
98
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cards/commerce-sdk",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.9",
|
|
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
|
"homepage": "https://opencommerce.sh",
|
|
6
6
|
"type": "module",
|