@agent-cards/commerce-sdk 0.18.4 → 0.18.6
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 +45 -2
- package/dist/action-links.js +1 -0
- package/dist/app-instructions.d.ts +17 -0
- package/dist/app-instructions.generated.d.ts +9 -0
- package/dist/app-instructions.generated.js +10 -0
- package/dist/app-instructions.js +22 -0
- package/dist/buy-tool.d.ts +21 -2
- package/dist/buy-tool.js +150 -67
- package/dist/client.d.ts +84 -11
- package/dist/client.js +101 -15
- package/dist/definition.js +2 -1
- package/dist/direct.d.ts +8 -0
- package/dist/direct.js +13 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/message.d.ts +2 -1
- package/dist/model-view.d.ts +29 -4
- package/dist/model-view.js +93 -13
- package/dist/plan.d.ts +41 -0
- package/dist/plan.js +34 -0
- package/dist/shopper-message.d.ts +12 -0
- package/dist/shopper-message.js +10 -0
- package/dist/store-wait.d.ts +27 -0
- package/dist/store-wait.js +41 -0
- package/dist/trip-ask.d.ts +1 -1
- package/dist/trip-ask.js +4 -4
- package/dist/turn-record.d.ts +2 -2
- package/dist/turn-record.js +3 -3
- package/examples/anthropic.mjs +3 -2
- package/package.json +4 -3
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
|
|
|
@@ -328,6 +339,34 @@ for await (const stream of runner) {
|
|
|
328
339
|
- A step link, the `vault`, `approval` or `store_login` page the shopper opens to go on, comes after the message that asks for it: the turn holds it until your model's next message stream ends (or `turn.say` is called), then sends it right after that message, so the shopper reads "add your card to place the order" and then taps. Product and store cards go out the moment the tool hands them over. A held link also goes out when the turn's next call starts, or after 20 seconds, so a model that writes nothing still sends it. `turn.say` and the stream's `end` resolve once the held links went out too, and reject when one failed to send, so your app never answers without a link the shopper needs; a link that failed to go out at the next call or the 20 seconds rejects the next reply that ends.
|
|
329
340
|
- Without `onItem`, pass `onMessage` beside `sendLink`, and write the model's text through `turn.messageStream()`: `onMessage` hears each message, paced, and `sendLink` hears each step link after the message that asks for it. An app that streams the model through the package's own `messageStream` gets each link the moment the tool hands it over, before the words about it.
|
|
330
341
|
|
|
342
|
+
## Keep one purchase per chat
|
|
343
|
+
|
|
344
|
+
A shopper who writes to your agent in several chats at once, such as group chats or threads, would otherwise continue one purchase from all of them. Build one tool per shopper and chat, and name the chat with `threadId`, your own id for it. Agentcard then keeps a purchase per chat: each chat's carts, questions and approvals stay in that chat, while the shopper keeps one Vault card, one store sign-in and one address book.
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
const buy = buyTool({ agentcard, externalUserId: shopper.id, threadId: chat.id }); // one per shopper and chat
|
|
348
|
+
```
|
|
349
|
+
|
|
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.
|
|
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
|
+
|
|
331
370
|
## Tell the model what Agentcard told the shopper
|
|
332
371
|
|
|
333
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.
|
|
@@ -517,6 +556,8 @@ const buy = buyTool({
|
|
|
517
556
|
|
|
518
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.
|
|
519
558
|
|
|
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.
|
|
560
|
+
|
|
520
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.
|
|
521
562
|
|
|
522
563
|
Code that calls the client itself streams with `agentcard.buy(body, handlers)`: `onCatalog`, `onSegment`, `onCart` and `onDelta` hear their events in the order Agentcard sent them, each once the one before it settled, and the answer waits for the last of them. `onDelta` asks Agentcard for the pieces of each message as it writes them, a draft that each `onSegment` message replaces.
|
|
@@ -707,6 +748,7 @@ Subscribe your endpoint to each event below by name. A catch-all `*` alone does
|
|
|
707
748
|
| `purchase.message` | `order_failed` | The order failed after the shopper approved. | Agentcard |
|
|
708
749
|
| `purchase.message` | `order_not_placed_yet` | The shopper approved, and the order is not placed yet. | Agentcard |
|
|
709
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 |
|
|
710
752
|
| `purchase.message` | `approval_expiring` | The approval link expires soon. `text` carries the link. | Agentcard |
|
|
711
753
|
| `purchase.message` | `approval_expired` | The approval expired before the shopper answered, and no charge went through. | Agentcard |
|
|
712
754
|
| `purchase.message` | `approval_declined` | The shopper declined the approval, and no charge went through. | Agentcard |
|
|
@@ -836,6 +878,7 @@ The facts are `merchantName`, `totalCents`, `currency`, `cardBrand`, `cardLast4`
|
|
|
836
878
|
| `card_link_expired` | The card link expired before the shopper added a card. |
|
|
837
879
|
| `cart_idle` | A cart sat, and nobody sent it for approval. |
|
|
838
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. |
|
|
839
882
|
| `card_added` | The shopper saved a card from the card link your app sent. |
|
|
840
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. |
|
|
841
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. |
|
package/dist/action-links.js
CHANGED
|
@@ -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.79";
|
|
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.79";
|
|
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
|
+
}
|
package/dist/buy-tool.d.ts
CHANGED
|
@@ -31,12 +31,14 @@
|
|
|
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 { BuyPlan } from './plan.js';
|
|
34
35
|
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';
|
|
35
36
|
import { type BuyToolDefinition, type BuyToolInput, type BuyToolInputSchema, type BuyToolStandardSchema, type OpenAIBuyTool } from './definition.js';
|
|
36
37
|
import { type DirectCall } from './direct.js';
|
|
37
38
|
import { type BuyToolModelView } from './model-view.js';
|
|
38
39
|
import { type MessagePace, type MessageStream } from './messages.js';
|
|
39
40
|
import { type ShopperMessage } from './shopper-message.js';
|
|
41
|
+
import { type BuyStoreWait } from './store-wait.js';
|
|
40
42
|
/**
|
|
41
43
|
* Where the purchase stands:
|
|
42
44
|
* - `needs_input`: Agentcard asks the shopper something, or shows a cart.
|
|
@@ -230,6 +232,8 @@ export interface BuyToolResult {
|
|
|
230
232
|
* message from Agentcard, and only the shopper's yes to that total confirms it.
|
|
231
233
|
*/
|
|
232
234
|
cart_building?: BuyCartBuilding | null;
|
|
235
|
+
/** 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. */
|
|
236
|
+
plan?: BuyPlan | null;
|
|
233
237
|
/**
|
|
234
238
|
* True when this call sent Agentcard a confirm: the shopper's yes, or the yes the tool carried past a step the shopper
|
|
235
239
|
* finished outside the chat. Absent when the call sent the shopper's words or read the conversation.
|
|
@@ -289,13 +293,20 @@ export interface BuyToolFound {
|
|
|
289
293
|
found: number;
|
|
290
294
|
more: BuyToolLink[];
|
|
291
295
|
}
|
|
292
|
-
export interface BuyToolOptions {
|
|
296
|
+
export interface BuyToolOptions extends BuyStoreWait {
|
|
293
297
|
/** A client built with your company's credentials. Build it once and share it across every shopper's tool. */
|
|
294
298
|
agentcard?: AgentcardClient;
|
|
295
299
|
/** Or one shopper's own Agentcard access token, for a tool that buys only for them. */
|
|
296
300
|
accessToken?: string;
|
|
297
301
|
/** Your own id for the shopper. Required with a company client, and left out with a shopper's own token. */
|
|
298
302
|
externalUserId?: string;
|
|
303
|
+
/**
|
|
304
|
+
* Your own id for the chat or thread this tool answers in, such as a group chat's id. Agentcard keeps one open purchase
|
|
305
|
+
* per thread for the shopper, so two chats never share a cart, a question or an approval, and the tool reads only the
|
|
306
|
+
* messages about this thread's purchase and those about the shopper alone, such as a saved card. Build one tool per
|
|
307
|
+
* shopper and thread. Leave it out for an app with one chat per shopper.
|
|
308
|
+
*/
|
|
309
|
+
threadId?: string;
|
|
299
310
|
/**
|
|
300
311
|
* Delivers a link to the shopper. Each call waits for it, so the shopper
|
|
301
312
|
* holds the link before the model answers. A `sendLink` that throws on a
|
|
@@ -550,7 +561,7 @@ export type BuyToolTurnItem = {
|
|
|
550
561
|
link: BuyToolLink;
|
|
551
562
|
};
|
|
552
563
|
/** 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`. */
|
|
553
|
-
export interface BuyToolTurnOptions {
|
|
564
|
+
export interface BuyToolTurnOptions extends BuyStoreWait {
|
|
554
565
|
/**
|
|
555
566
|
* Hears everything the turn hands the shopper, one item at a time and in the order it happened: the
|
|
556
567
|
* instant reply and each message your model writes through `turn.messageStream()` or `turn.say()` as
|
|
@@ -615,6 +626,14 @@ export interface BuyToolTurnOptions {
|
|
|
615
626
|
onText?: BuyToolOptions['onText'];
|
|
616
627
|
/** Hears the carts each time a call of this turn builds or changes one, as the tool's `onCart` does. */
|
|
617
628
|
onCart?: BuyToolOptions['onCart'];
|
|
629
|
+
/**
|
|
630
|
+
* The card the shopper tapped to open this turn, by the `productId` its link carried, whatever answer showed it. With `direct`
|
|
631
|
+
* on, the turn's call goes straight to Agentcard as a pick of exactly that card (`turn.direct`, reason `pick`), and Agentcard
|
|
632
|
+
* 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.
|
|
633
|
+
*/
|
|
634
|
+
tapped?: {
|
|
635
|
+
productId: string;
|
|
636
|
+
};
|
|
618
637
|
}
|
|
619
638
|
/**
|
|
620
639
|
* The buy tool for one shopper message, from `buy.turn`. It is the same tool, with the same name,
|