@agent-cards/commerce-sdk 0.18.5 → 0.18.7

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 CHANGED
@@ -51,7 +51,7 @@ Build one client with your company's credentials and one buy tool per shopper, t
51
51
 
52
52
  ```ts
53
53
  import Anthropic from '@anthropic-ai/sdk';
54
- import { AgentcardClient, buyTool } from '@agent-cards/commerce-sdk';
54
+ import { AgentcardClient, appInstructions, buyTool } from '@agent-cards/commerce-sdk';
55
55
 
56
56
  const agentcard = new AgentcardClient({
57
57
  clientId: process.env.AGENTCARD_CLIENT_ID ?? '',
@@ -67,6 +67,7 @@ const buy = buyTool({
67
67
  const answer = await new Anthropic().beta.messages.toolRunner({
68
68
  model: 'claude-opus-5-5',
69
69
  max_tokens: 16000,
70
+ system: appInstructions({ markdown: true }),
70
71
  tools: [buy],
71
72
  messages: [{ role: 'user', content: 'two packs of AA batteries from Amazon' }],
72
73
  });
@@ -78,6 +79,16 @@ Build the client once and keep it. Every shopper's tool shares the client's acce
78
79
 
79
80
  The model sends `ask`, `confirm`, `new_order`, `product_id` and `store_id`, and nothing else. A product link the shopper sends, such as a `buy.trychannel3.com` link, goes in `ask` exactly as sent, and Agentcard buys that exact product from it. Pass `deliveryAddress` when you already hold the shopper's address: the order goes there, and Agentcard never asks the shopper for it. The model can change neither the address nor the shopper.
80
81
 
82
+ ## Give your model Agentcard's instructions
83
+
84
+ `appInstructions()` returns the system prompt Agentcard recommends for your model: what Agentcard can do for the shopper, in the words Agentcard's own buy agent uses, how to hand a request to the buy tool, and how to write for your app. Put it first in your system prompt, and add only what is about your app, such as its name:
85
+
86
+ ```ts
87
+ const system = [appInstructions({ markdown: true, textingStyle: true }), 'You are the shopping chat in Acme.'].join('\n\n');
88
+ ```
89
+
90
+ Pass `markdown: true` when your app shows the model's words as Markdown, so a shopper who asks for a table gets one; leave it out and the model writes plain text, with lists as `• ` lines. Pass `textingStyle: true` when your app is a chat that writes in lowercase, as you pass it to `buyTool`. The text ships inside the package and changes with each release; `APP_INSTRUCTIONS_VERSION` names the version you run.
91
+
81
92
  ## Use the tool in any framework
82
93
 
83
94
  Pass `buy` as it is. Each framework reads its own fields from the same object, so you pick no adapter:
@@ -152,7 +163,7 @@ Each step ends with a shopper message: `actionLinkOutcome(link, message)` says h
152
163
  | --- | --- | --- | --- | --- |
153
164
  | `vault` | `card_added` | | | `card_link_expired` |
154
165
  | `store_login` | `store_connected` | | `store_connect_failed` | `store_connect_expired` |
155
- | `approval` | `order_placed`, `order_not_placed_yet`, `order_unconfirmed`, `order_confirmed`, `order_failed`, `payment_declined` | `approval_declined` | | `approval_expired` |
166
+ | `approval` | `order_placing`, `order_placed`, `order_not_placed_yet`, `order_unconfirmed`, `order_confirmed`, `order_failed`, `payment_declined` | `approval_declined` | | `approval_expired` |
156
167
 
157
168
  A reminder, such as `card_link_unfinished` or `approval_expiring`, leaves the step open. An approval is `completed` once the shopper approved, even when the order then failed or the payment was refused: the approval page has nothing more to do, and the message tells the shopper what happened. A message whose facts name another link of the same kind (`facts.approvalUrl`, `facts.cardLinkUrl`) leaves this one open, and so does one about another store: a store login link names its store in `store`, and so does an approval link when the answer names the cart's store, so DoorDash's `store_connected` (`facts.merchantName: 'DoorDash'`) never ends a Locale sign-in the shopper has open beside it.
158
169
 
@@ -338,6 +349,24 @@ const buy = buyTool({ agentcard, externalUserId: shopper.id, threadId: chat.id }
338
349
 
339
350
  A message about one chat's purchase carries that chat as `threadId`, so post it into that chat. One about the shopper alone, such as a saved card, carries `threadId: null`. A chat's tool takes a next step only for its own chat's messages and the shopper's own, and a tool built without `threadId` only for purchases opened under no thread and the shopper's own.
340
351
 
352
+ ## Choose how long a reply waits for stores
353
+
354
+ A search that asks several stores writes its reply once the stores answered or a wait ran out. Choose that wait with `storeWaitMs`, and choose with `lateResults` what happens to a store that answers after the reply:
355
+
356
+ ```ts
357
+ // A streaming chat: cards show as each store answers, the reply waits up to 25 s (99.7% of stores' first products), and a later store's cards stream below it.
358
+ const buy = buyTool({ agentcard, externalUserId: shopper.id, storeWaitMs: 25000, lateResults: 'stream' });
359
+ // A texting app: the reply waits up to 20 s (96% of stores' first products) and is the turn's last word.
360
+ const sms = buyTool({ agentcard, externalUserId: shopper.id, storeWaitMs: 20000, lateResults: 'hold' });
361
+ ```
362
+
363
+ Agentcard ends every store search at 30 s, so a `storeWaitMs` above `30000` waits no longer than `30000` does.
364
+
365
+ - `lateResults: 'stream'` sends a late store's cards after the reply, in the same turn, the way a slower hotel supplier's cards come: to `sendLink`, `onProducts` and `onItem`, with the one message that says what they added. The turn's `onResult` lists them in `result.products` after the answer's own.
366
+ - `lateResults: 'hold'` keeps a late store's cards out of the turn, so a texting app never sends a card after the reply.
367
+ - `buy.turn(message, { storeWaitMs, lateResults })` sets them for one turn, and each one left out keeps the tool's. An app that calls `client.buy` itself sends `store_wait_ms` and `late_results`.
368
+ - Left out, the tool sends neither, and Agentcard keeps its own wait. A wait that is not a whole number of milliseconds, 0 or more, throws a TypeError before any call.
369
+
341
370
  ## Tell the model what Agentcard told the shopper
342
371
 
343
372
  Agentcard posts messages into the shopper's chat between turns, through `listen` or the webhook: `Your Visa ending 3132 is saved, so you're ready to check out.`, an order placed, an approval about to expire. The shopper reads them, so your model has to know them too. A model that never saw `card_added` answers "ok lets checkout" with "did you save your card?" and never calls the tool.
@@ -527,7 +556,7 @@ const buy = buyTool({
527
556
 
528
557
  When your app shows Agentcard's messages through `onText`, the model reads `shopper_already_read_reply: true` in that call's answer and adds nothing to them, as it reads `shopper_already_told_looking` after an instant reply: end the turn without a second model call, as with `replyAsWritten`, or let the model add one short line for what the reply left out. `turn.replyAsWritten` stays null for that answer, so the reply never reaches the shopper twice, and a step link the turn holds for your model's next message goes out right after Agentcard's ask instead.
529
558
 
530
- A turn built with `replyAsWritten` and `earlyCards` that hears messages through `onMessage` or `onItem` and passes no `onText` gets the same once a reply is written while a slower source's cards are still coming, such as a second hotel supplier's: Agentcard's messages go out through that callback the moment Agentcard says the reply is written, the slower cards and their one message follow in the same call, and the answer reads `shopper_already_read_reply: true` with `turn.replyAsWritten` null.
559
+ A turn built with `replyAsWritten` and `earlyCards` that hears messages through `onMessage` or `onItem` and passes no `onText` gets the same once a reply is written while a slower source's cards are still coming, such as a second hotel supplier's: Agentcard's messages go out through that callback the moment Agentcard says the reply is written, the slower cards and their one message follow in the same call, and the answer reads `shopper_already_read_reply: true`. `turn.replyAsWritten` then holds the messages the shopper read, and `turn.say` of it sends nothing, so an app that shows the reply as written and skips its model shows no second reply.
531
560
 
532
561
  A stream that breaks after the call started reads the conversation for what the turn left, as a turn past Agentcard's budget does. Pass `stream: false` to wait for each whole answer, with its cards sent beside it.
533
562
 
@@ -719,6 +748,7 @@ Subscribe your endpoint to each event below by name. A catch-all `*` alone does
719
748
  | `purchase.message` | `order_failed` | The order failed after the shopper approved. | Agentcard |
720
749
  | `purchase.message` | `order_not_placed_yet` | The shopper approved, and the order is not placed yet. | Agentcard |
721
750
  | `purchase.message` | `order_unconfirmed` | The store's reply to the order was lost, so the order may exist, and Agentcard is confirming it. | Agentcard |
751
+ | `purchase.message` | `order_placing` | The shopper approved, and Agentcard is placing the order now. One of the order kinds above follows. | Agentcard |
722
752
  | `purchase.message` | `approval_expiring` | The approval link expires soon. `text` carries the link. | Agentcard |
723
753
  | `purchase.message` | `approval_expired` | The approval expired before the shopper answered, and no charge went through. | Agentcard |
724
754
  | `purchase.message` | `approval_declined` | The shopper declined the approval, and no charge went through. | Agentcard |
@@ -848,6 +878,7 @@ The facts are `merchantName`, `totalCents`, `currency`, `cardBrand`, `cardLast4`
848
878
  | `card_link_expired` | The card link expired before the shopper added a card. |
849
879
  | `cart_idle` | A cart sat, and nobody sent it for approval. |
850
880
  | `order_unconfirmed` | The store's reply to the order was lost, and Agentcard is confirming it. |
881
+ | `order_placing` | The shopper approved, and Agentcard is placing the order now. The order's own message follows. |
851
882
  | `card_added` | The shopper saved a card from the card link your app sent. |
852
883
  | `store_connected` | The shopper signed in to their own account at the store from the sign-in link your app sent, such as DoorDash, so the order can go through on it. |
853
884
  | `store_connect_failed` | The shopper's sign-in to the store did not go through, and the link no longer works. `text` offers a new one. |
@@ -14,6 +14,7 @@ export const ACTION_LINK_ENDINGS = {
14
14
  vault: { card_added: 'completed', card_link_expired: 'expired' },
15
15
  store_login: { store_connected: 'completed', store_connect_failed: 'failed', store_connect_expired: 'expired' },
16
16
  approval: {
17
+ order_placing: 'completed',
17
18
  order_placed: 'completed',
18
19
  order_not_placed_yet: 'completed',
19
20
  order_unconfirmed: 'completed',
@@ -0,0 +1,17 @@
1
+ /** The version of the text `appInstructions` returns. It changes whenever the text does. */
2
+ export declare const APP_INSTRUCTIONS_VERSION: string;
3
+ export interface AppInstructionsOptions {
4
+ /** `true` when your app shows the model's words as Markdown: tables, lists and bold. Default `false`, plain text. */
5
+ markdown?: boolean;
6
+ /**
7
+ * `true` when your app is a chat that writes like a text message: all lowercase except names. Pass the same value
8
+ * you pass `buyTool` as `textingStyle`. Default `false`.
9
+ */
10
+ textingStyle?: boolean;
11
+ }
12
+ /**
13
+ * The lines to put in your model's system prompt, before your own. Add only what is about your app, such as its name
14
+ * or what a shopper sees on its screen; what Agentcard can do and how to use the buy tool come from here, so they
15
+ * change with each SDK release.
16
+ */
17
+ export declare function appInstructions(options?: AppInstructionsOptions): string;
@@ -0,0 +1,9 @@
1
+ /** The version of the voice package the text was copied from. */
2
+ export declare const VOICE_VERSION = "0.2.80";
3
+ export declare const APP_TEXT: {
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
+ 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.";
6
+ readonly plainText: "The app shows your words as plain text, so write no Markdown: asterisks, underscores, pound signs, backticks and table pipes show up as written. Write a list as lines that start with \"• \", and a table the shopper asks for as one line per row.";
7
+ readonly texting: "Write like a text message: all lowercase except names, short and plain, with no dashes.";
8
+ readonly standard: "Write short, plain sentences, the way a person writes in a chat.";
9
+ };
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/app-instructions.mjs from apps/agent-voice/kb/app.md. Do not edit: edit kb/app.md.
2
+ /** The version of the voice package the text was copied from. */
3
+ export const VOICE_VERSION = "0.2.80";
4
+ export const APP_TEXT = {
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
+ "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.",
7
+ "plainText": "The app shows your words as plain text, so write no Markdown: asterisks, underscores, pound signs, backticks and table pipes show up as written. Write a list as lines that start with \"• \", and a table the shopper asks for as one line per row.",
8
+ "texting": "Write like a text message: all lowercase except names, short and plain, with no dashes.",
9
+ "standard": "Write short, plain sentences, the way a person writes in a chat."
10
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The system prompt Agentcard recommends for your own model, the one that holds the buy tool and talks to the
3
+ * shopper. The buy tool's description says how to call it; these lines say who the model is for the shopper: what
4
+ * Agentcard can do, in the same words Agentcard's buy agent uses, how the model hands a request to the tool, and
5
+ * how its words look in your app. The text is copied from the voice package (apps/agent-voice/kb/app.md) when the
6
+ * SDK is built, so it ships inside the package and costs no request.
7
+ */
8
+ import { APP_TEXT, VOICE_VERSION } from './app-instructions.generated.js';
9
+ /** The version of the text `appInstructions` returns. It changes whenever the text does. */
10
+ export const APP_INSTRUCTIONS_VERSION = VOICE_VERSION;
11
+ /**
12
+ * The lines to put in your model's system prompt, before your own. Add only what is about your app, such as its name
13
+ * or what a shopper sees on its screen; what Agentcard can do and how to use the buy tool come from here, so they
14
+ * change with each SDK release.
15
+ */
16
+ export function appInstructions(options = {}) {
17
+ return [
18
+ APP_TEXT.core,
19
+ options.markdown ? APP_TEXT.markdown : APP_TEXT.plainText,
20
+ options.textingStyle ? APP_TEXT.texting : APP_TEXT.standard,
21
+ ].join('\n\n');
22
+ }
@@ -31,12 +31,16 @@
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 { AgentcardClient, type BuyCart, type BuyCartBuilding, type BuyChoice, type BuyFlightItinerary, type BuyDeliveryAddress, type BuyNextAction, type BuyPick, type BuyProgress, type BuyTurnStatus, type BuyAvailability, type BuyStorePick, type BuyTurn, type FetchLike } from './client.js';
34
+ import type { BuyPlan } from './plan.js';
35
+ import type { BuyMerchantStatusUpdate, BuySearchStatus } from './search-status.js';
36
+ import type { BuyFulfilledBy } from './fulfilled-by.js';
37
+ import { AgentcardClient, type BuyCart, type BuyCartBuilding, type BuyChoice, type BuyCodeRequest, type BuyFlightItinerary, type BuyDeliveryAddress, type BuyNextAction, type BuyPick, type BuyProgress, type BuyTurnStatus, type BuyAvailability, type BuyStorePick, type BuyTurn, type FetchLike } from './client.js';
35
38
  import { type BuyToolDefinition, type BuyToolInput, type BuyToolInputSchema, type BuyToolStandardSchema, type OpenAIBuyTool } from './definition.js';
36
39
  import { type DirectCall } from './direct.js';
37
40
  import { type BuyToolModelView } from './model-view.js';
38
41
  import { type MessagePace, type MessageStream } from './messages.js';
39
42
  import { type ShopperMessage } from './shopper-message.js';
43
+ import { type BuyStoreWait } from './store-wait.js';
40
44
  /**
41
45
  * Where the purchase stands:
42
46
  * - `needs_input`: Agentcard asks the shopper something, or shows a cart.
@@ -88,6 +92,11 @@ export interface BuyToolLink {
88
92
  storeDomain?: string | null;
89
93
  /** On a product link: the product's name. */
90
94
  title?: string;
95
+ /**
96
+ * On a product link: who sells or books the product, where that is not the store it names, such as a ticket's
97
+ * `{ name: 'StubHub', kind: 'marketplace', line: 'via StubHub' }`. Show `line` quietly under the price. Absent when none.
98
+ */
99
+ fulfilledBy?: BuyFulfilledBy;
91
100
  /**
92
101
  * On a product link: what taking the product does, so a button can say it. `reserve` is a table the
93
102
  * shopper reserves, `book` a flight, room, class or ticket they book, and `buy` anything they buy.
@@ -175,6 +184,8 @@ export interface BuyToolProduct {
175
184
  linkSent: boolean;
176
185
  /** For a place to book: whether it has room at the asked time. Absent on a product with no such question. */
177
186
  availability?: BuyAvailability;
187
+ /** Who sells or books it, where that is not the store it names (`via StubHub`); absent when Agentcard named none. */
188
+ fulfilledBy?: BuyFulfilledBy;
178
189
  }
179
190
  /** One answer of the buy tool, whole, for your code. Hand it to `forModel` before a model reads it. */
180
191
  export interface BuyToolResult {
@@ -230,6 +241,10 @@ export interface BuyToolResult {
230
241
  * message from Agentcard, and only the shopper's yes to that total confirms it.
231
242
  */
232
243
  cart_building?: BuyCartBuilding | null;
244
+ /** The checkout plan the answer started or moved, such as a trip's flight, hotel and car with each one's state; null when none. */
245
+ plan?: BuyPlan | null;
246
+ /** Every store the answer's searches asked and where each stands (`searchAt` narrows it to one store); null when it searched none. */
247
+ search?: BuySearchStatus | null;
233
248
  /**
234
249
  * True when this call sent Agentcard a confirm: the shopper's yes, or the yes the tool carried past a step the shopper
235
250
  * finished outside the chat. Absent when the call sent the shopper's words or read the conversation.
@@ -254,6 +269,8 @@ export interface BuyToolResult {
254
269
  * values one per line under the question. Absent or null when the reply asks none.
255
270
  */
256
271
  choice?: BuyChoice | null;
272
+ /** The wallet's code a store checkout waits for, so an app can show a code box beside the reply; absent or null when none. */
273
+ code_request?: BuyCodeRequest | null;
257
274
  /** Agentcard's answer as it came: the purchase answer, or the body of the refusal. */
258
275
  envelope: Record<string, unknown>;
259
276
  }
@@ -289,7 +306,7 @@ export interface BuyToolFound {
289
306
  found: number;
290
307
  more: BuyToolLink[];
291
308
  }
292
- export interface BuyToolOptions {
309
+ export interface BuyToolOptions extends BuyStoreWait {
293
310
  /** A client built with your company's credentials. Build it once and share it across every shopper's tool. */
294
311
  agentcard?: AgentcardClient;
295
312
  /** Or one shopper's own Agentcard access token, for a tool that buys only for them. */
@@ -385,6 +402,11 @@ export interface BuyToolOptions {
385
402
  * throws costs nothing but the call to it.
386
403
  */
387
404
  onAvailability?: (update: BuyToolAvailability) => void | Promise<void>;
405
+ /**
406
+ * Hears each store a call's searches ask, the moment its status changes (`BuyMerchantStatusUpdate`): `searching` when its
407
+ * search starts, then what it found. One that throws costs nothing but the call to it.
408
+ */
409
+ onMerchantStatus?: (update: BuyMerchantStatusUpdate) => void | Promise<void>;
388
410
  /**
389
411
  * Hears the products a call's search found, the moment the search answers and before Agentcard writes its reply,
390
412
  * with the conversation, when the search ran (`asOf`, as the answer's `catalog.as_of` names it) and the store's name.
@@ -557,7 +579,7 @@ export type BuyToolTurnItem = {
557
579
  link: BuyToolLink;
558
580
  };
559
581
  /** The callbacks of one turn. Each one left out falls back to the option of the same name the tool was built with, except with `onItem`. */
560
- export interface BuyToolTurnOptions {
582
+ export interface BuyToolTurnOptions extends BuyStoreWait {
561
583
  /**
562
584
  * Hears everything the turn hands the shopper, one item at a time and in the order it happened: the
563
585
  * instant reply and each message your model writes through `turn.messageStream()` or `turn.say()` as
@@ -612,6 +634,8 @@ export interface BuyToolTurnOptions {
612
634
  onFound?: BuyToolOptions['onFound'];
613
635
  /** Hears whether the places this turn's cards show have room, as the tool's `onAvailability` does. */
614
636
  onAvailability?: BuyToolOptions['onAvailability'];
637
+ /** Hears each store this turn's searches ask, as the tool's `onMerchantStatus` does. */
638
+ onMerchantStatus?: BuyToolOptions['onMerchantStatus'];
615
639
  /** Hears the products each search of this turn's calls found, the moment it answers, as the tool's `onProducts` does. */
616
640
  onProducts?: BuyToolOptions['onProducts'];
617
641
  /**
@@ -622,6 +646,14 @@ export interface BuyToolTurnOptions {
622
646
  onText?: BuyToolOptions['onText'];
623
647
  /** Hears the carts each time a call of this turn builds or changes one, as the tool's `onCart` does. */
624
648
  onCart?: BuyToolOptions['onCart'];
649
+ /**
650
+ * The card the shopper tapped to open this turn, by the `productId` its link carried, whatever answer showed it. With `direct`
651
+ * on, the turn's call goes straight to Agentcard as a pick of exactly that card (`turn.direct`, reason `pick`), and Agentcard
652
+ * carts it, so a tap on a card two answers back carts that card. Send the tap's words as the turn's message too.
653
+ */
654
+ tapped?: {
655
+ productId: string;
656
+ };
625
657
  }
626
658
  /**
627
659
  * The buy tool for one shopper message, from `buy.turn`. It is the same tool, with the same name,