@alexkroman1/aai-cli 7.0.0 → 8.0.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 +1 -0
- package/dist/{_bundler-B4RqNF5Z.mjs → _bundler-CDuYl5Gb.mjs} +1 -1
- package/dist/{_dev-server-CiKFH9qw.mjs → _dev-server-Me06wgeF.mjs} +2 -2
- package/dist/{_init-CE4HKdgV.mjs → _init-BhEfQ6Yi.mjs} +1 -1
- package/dist/_resource-commands.d.ts +23 -0
- package/dist/{_slug-api-nRFaBEPJ.mjs → _slug-api-z-USxPtL.mjs} +14 -10
- package/dist/_slug-api.d.ts +5 -2
- package/dist/{_templates-FI3xPEMj.mjs → _templates-4WcKOjS5.mjs} +4 -5
- package/dist/_templates.d.ts +3 -4
- package/dist/{build-6jfaakgc.mjs → build-BBxf8vom.mjs} +2 -2
- package/dist/cli.mjs +338 -346
- package/dist/{deploy-DvYeD8ia.mjs → deploy-DRC8jWr8.mjs} +1 -1
- package/dist/{dev-B59JIfWO.mjs → dev-BvcctCn2.mjs} +1 -1
- package/dist/eval-DfQ8cm5p.mjs +56 -0
- package/dist/eval.d.ts +43 -0
- package/dist/{init-CpJVjEg0.mjs → init-CUo87gcI.mjs} +2 -2
- package/dist/{logs-9q-psa4q.mjs → logs-CQ2T46dr.mjs} +1 -1
- package/dist/scaffold/CLAUDE.md +409 -68
- package/dist/scaffold/package.json +5 -4
- package/dist/scaffold/server.mjs +10 -3
- package/dist/scaffold/tsconfig.json +0 -1
- package/dist/{secret-CVvSLIDV.mjs → secret-Ct34kdgU.mjs} +1 -1
- package/dist/{storage-BvUrnvM3.mjs → storage-i_79ZwAR.mjs} +1 -1
- package/dist/{studio--MUV0cid.mjs → studio-CzTzPqe1.mjs} +1 -1
- package/dist/templates/briefing-desk/agent.test.ts +350 -0
- package/dist/templates/briefing-desk/agent.ts +30 -0
- package/dist/templates/briefing-desk/shared.ts +200 -0
- package/dist/templates/briefing-desk/system-prompt.md +39 -0
- package/dist/templates/briefing-desk/tools/briefing_so_far.ts +35 -0
- package/dist/templates/briefing-desk/tools/research_topic.ts +88 -0
- package/dist/templates/briefing-desk/tools/verify_claim.ts +77 -0
- package/dist/templates/call-audit/agent.eval.test.ts +474 -0
- package/dist/templates/code-interpreter/agent.eval.test.ts +165 -0
- package/dist/templates/dispatch-center/agent.eval.test.ts +349 -0
- package/dist/templates/embedded-assets/agent.eval.test.ts +138 -0
- package/dist/templates/health-assistant/agent.eval.test.ts +167 -0
- package/dist/templates/infocom-adventure/agent.eval.test.ts +158 -0
- package/dist/templates/infocom-adventure/agent.test.ts +49 -18
- package/dist/templates/infocom-adventure/agent.ts +21 -0
- package/dist/templates/infocom-adventure/shared.ts +20 -9
- package/dist/templates/infocom-adventure/system-prompt.md +1 -1
- package/dist/templates/infocom-adventure/tools/game_state_move.ts +3 -2
- package/dist/templates/link-digest/agent.eval.test.ts +195 -0
- package/dist/templates/math-buddy/agent.eval.test.ts +146 -0
- package/dist/templates/night-owl/agent.eval.test.ts +272 -0
- package/dist/templates/personal-finance/agent.eval.test.ts +168 -0
- package/dist/templates/personal-finance/system-prompt.md +4 -0
- package/dist/templates/pipeline-simple/agent.eval.test.ts +78 -0
- package/dist/templates/pipeline-simple/agent.ts +2 -2
- package/dist/templates/pizza-ordering/agent.eval.test.ts +171 -0
- package/dist/templates/pizza-ordering/agent.test.ts +15 -0
- package/dist/templates/pizza-ordering/shared.ts +20 -1
- package/dist/templates/pizza-ordering/system-prompt.md +6 -0
- package/dist/templates/plan-and-execute/agent.eval.test.ts +209 -0
- package/dist/templates/podcast-digest/agent.eval.test.ts +411 -0
- package/dist/templates/podcast-digest/agent.test.ts +30 -59
- package/dist/templates/podcast-digest/agent.ts +1 -1
- package/dist/templates/podcast-digest/workflows/digest.ts +52 -19
- package/dist/templates/podcast-digest/workflows/slack.ts +48 -169
- package/dist/templates/recap-workflow/agent.eval.test.ts +366 -0
- package/dist/templates/redline/agent.eval.test.ts +209 -0
- package/dist/templates/research-workflow/agent.eval.test.ts +329 -0
- package/dist/templates/retail/address.ts +87 -1
- package/dist/templates/retail/agent.eval.test.ts +314 -0
- package/dist/templates/retail/agent.test.ts +171 -91
- package/dist/templates/retail/agent.ts +35 -1
- package/dist/templates/retail/cancel.ts +116 -0
- package/dist/templates/retail/client.tsx +39 -0
- package/dist/templates/retail/payment.ts +107 -0
- package/dist/templates/retail/pending.test.ts +196 -0
- package/dist/templates/retail/pending.ts +137 -0
- package/dist/templates/retail/registry.test.ts +119 -8
- package/dist/templates/retail/returns.ts +102 -0
- package/dist/templates/retail/shared.test.ts +42 -0
- package/dist/templates/retail/shared.ts +35 -0
- package/dist/templates/retail/store.test.ts +6 -4
- package/dist/templates/retail/store.ts +113 -57
- package/dist/templates/retail/swap.test.ts +4 -4
- package/dist/templates/retail/swap.ts +248 -15
- package/dist/templates/retail/system-prompt.md +62 -30
- package/dist/templates/retail/tools/cancel_change.ts +33 -0
- package/dist/templates/retail/tools/cancel_pending_order.ts +15 -59
- package/dist/templates/retail/tools/confirm_change.ts +42 -0
- package/dist/templates/retail/tools/exchange_delivered_order_items.ts +21 -66
- package/dist/templates/retail/tools/modify_pending_order_address.ts +12 -24
- package/dist/templates/retail/tools/modify_pending_order_items.ts +22 -60
- package/dist/templates/retail/tools/modify_pending_order_payment.ts +15 -77
- package/dist/templates/retail/tools/modify_user_address.ts +12 -15
- package/dist/templates/retail/tools/return_delivered_order_items.ts +16 -71
- package/dist/templates/retail/tools/transfer_to_human_agents.ts +4 -2
- package/dist/templates/simple/agent.eval.test.ts +54 -0
- package/dist/templates/solo-rpg/agent.eval.test.ts +320 -0
- package/dist/templates/spoken-summary/agent.eval.test.ts +342 -0
- package/dist/templates/support-line/agent.eval.test.ts +273 -0
- package/dist/templates/support-line/system-prompt.md +2 -1
- package/dist/templates/support-line/tools/answer_question.ts +56 -7
- package/dist/templates/transcription-workflow/agent.eval.test.ts +234 -0
- package/dist/templates/travel-concierge/agent.eval.test.ts +323 -0
- package/dist/templates/travel-concierge/agent.test.ts +110 -10
- package/dist/templates/travel-concierge/agent.ts +18 -9
- package/dist/templates/travel-concierge/shared.ts +110 -9
- package/dist/templates/travel-concierge/system-prompt.md +7 -1
- package/dist/templates/travel-concierge/tools/book_car_rental.ts +6 -3
- package/dist/templates/travel-concierge/tools/book_excursion.ts +6 -3
- package/dist/templates/travel-concierge/tools/book_hotel.ts +6 -3
- package/dist/templates/travel-concierge/tools/cancel_ticket.ts +6 -3
- package/dist/templates/travel-concierge/tools/search_car_rentals.ts +9 -5
- package/dist/templates/travel-concierge/tools/search_excursions.ts +9 -5
- package/dist/templates/travel-concierge/tools/search_flights.ts +9 -6
- package/dist/templates/travel-concierge/tools/search_hotels.ts +9 -5
- package/dist/templates/travel-concierge/tools/update_ticket.ts +6 -3
- package/dist/templates/web-researcher/agent.eval.test.ts +121 -0
- package/dist/templates/web-researcher/system-prompt.md +15 -4
- package/dist/{test-9kPKJI-w.mjs → test-BvyT6sAc.mjs} +24 -10
- package/dist/test.d.ts +29 -5
- package/dist/{worker-bundler-COxnqstQ.mjs → worker-bundler-CCVEDjm1.mjs} +45 -25
- package/dist/worker-bundler.mjs +1 -1
- package/dist/{workflow-D2AQf2Pl.mjs → workflow-BflATMmU.mjs} +19 -11
- package/package.json +5 -5
- package/dist/eject-C9WJyyr2.mjs +0 -116
- package/dist/eject.d.ts +0 -60
- package/dist/templates/infocom-adventure/tools/game_state_history.ts +0 -14
|
@@ -10,16 +10,33 @@ next. Read it — it is the shortest true statement of what you may do, and you
|
|
|
10
10
|
not have to remember it between turns. A tool that is not available yet refuses
|
|
11
11
|
outright and tells you what has to happen first.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Three of the rules below are that machine rather than prose, and they are the
|
|
14
|
+
three you cannot get wrong by forgetting: you cannot act before you know who is
|
|
15
|
+
calling, you cannot act after the call has gone to a human, and you cannot
|
|
16
|
+
change anything the customer has not said yes to.
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
— by email (`find_user_id_by_email`), or by first name, last name and zip code
|
|
17
|
-
(`find_user_id_by_name_zip`) if they cannot remember the email. Do this **even
|
|
18
|
-
if the caller volunteers their user id**. Until you have, every other tool will
|
|
19
|
-
refuse.
|
|
18
|
+
# Nothing changes until the customer says yes
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
**No tool here changes anything.** Cancelling, modifying, returning and
|
|
21
|
+
exchanging all do the same thing: they check the request, price it, and hand
|
|
22
|
+
you one sentence describing exactly what would happen. Nothing has happened at
|
|
23
|
+
that point.
|
|
24
|
+
|
|
25
|
+
So every change is three steps, and they are three separate turns:
|
|
26
|
+
|
|
27
|
+
1. Call the tool for the change. It answers with a sentence.
|
|
28
|
+
2. **Say that sentence to the customer** — the order, the items, the amounts,
|
|
29
|
+
where the money is going — and stop. Ask them plainly: is that right?
|
|
30
|
+
3. On an explicit "yes", call `confirm_change`. On anything else — "no",
|
|
31
|
+
hesitation, "wait", a correction, a new subject — call `cancel_change` and
|
|
32
|
+
start again from what they actually want.
|
|
33
|
+
|
|
34
|
+
Never treat silence, a "mm-hm" in the middle of your sentence, or the fact that
|
|
35
|
+
they asked for it a minute ago as a yes. If you are not sure they agreed, ask
|
|
36
|
+
again; nothing is lost by asking, because nothing has happened yet.
|
|
37
|
+
|
|
38
|
+
Only one change can be waiting at a time. If you need to stage a different one,
|
|
39
|
+
settle the first with `confirm_change` or `cancel_change`.
|
|
23
40
|
|
|
24
41
|
# One customer per call
|
|
25
42
|
|
|
@@ -28,12 +45,9 @@ requests from that person, but you must refuse anything to do with anybody
|
|
|
28
45
|
else's account, and you cannot switch to a different customer mid-call — ask
|
|
29
46
|
them to call back.
|
|
30
47
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
say what you are about to do, including the order, the items, the amounts and
|
|
35
|
-
where money is going, and wait for an explicit "yes". Never act on an implied
|
|
36
|
-
yes.
|
|
48
|
+
Identify them by email (`find_user_id_by_email`), or by first name, last name
|
|
49
|
+
and zip code (`find_user_id_by_name_zip`) if they cannot remember the email.
|
|
50
|
+
Prefer email. Do this **even if the caller volunteers their user id**.
|
|
37
51
|
|
|
38
52
|
# Never invent anything
|
|
39
53
|
|
|
@@ -51,10 +65,23 @@ speak; when you speak, do not also make a tool call.
|
|
|
51
65
|
# Handing off to a human
|
|
52
66
|
|
|
53
67
|
Transfer only if the caller explicitly asks for a human, or their request
|
|
54
|
-
cannot be handled with your tools and this policy.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
for
|
|
68
|
+
cannot be handled with your tools and this policy.
|
|
69
|
+
|
|
70
|
+
**The handoff is a tool call, not a sentence.** Every turn in which the customer
|
|
71
|
+
asks for a person — "a real person", "an agent", "a supervisor", "put me
|
|
72
|
+
through", "this isn't working" — begins with a call to
|
|
73
|
+
`transfer_to_human_agents`. Not a question back, not an offer to try once more,
|
|
74
|
+
and not the sentence below. Do not ask what the problem is first, and do not try
|
|
75
|
+
to talk them out of it.
|
|
76
|
+
|
|
77
|
+
**Never say "You are being transferred" unless `transfer_to_human_agents` has
|
|
78
|
+
already answered in this turn.** Saying it without the call leaves the customer
|
|
79
|
+
holding a line nobody is coming to: nothing has been handed anywhere, and the
|
|
80
|
+
call is still yours. That is the one mistake here you cannot take back.
|
|
81
|
+
|
|
82
|
+
Once the tool has answered, say exactly: "You are being transferred to a human
|
|
83
|
+
agent. Please hold on." Say nothing else after that. The call is over for you at
|
|
84
|
+
that point, and every tool will refuse — including that one.
|
|
58
85
|
|
|
59
86
|
# Speaking on the phone
|
|
60
87
|
|
|
@@ -67,6 +94,9 @@ for you at that point, and every tool will refuse — including that one.
|
|
|
67
94
|
- When a customer gives you a number, read it back before you use it.
|
|
68
95
|
- Prices: "three hundred and twenty dollars and fifty cents", not "320.50".
|
|
69
96
|
- Keep replies to one or two sentences. This is a phone call, not an email.
|
|
97
|
+
The one place to be longer is the readback in step 2 above — that sentence
|
|
98
|
+
earns its length, and rushing it is the whole failure mode it exists to
|
|
99
|
+
prevent.
|
|
70
100
|
- Do not spell out tool names, statuses in snake_case, or user ids.
|
|
71
101
|
|
|
72
102
|
# What the tools accept
|
|
@@ -80,22 +110,25 @@ product's options.
|
|
|
80
110
|
|
|
81
111
|
# The rules that bite
|
|
82
112
|
|
|
113
|
+
Every rule here is checked when you stage a change, so a request that breaks one
|
|
114
|
+
is refused before the customer is ever asked to agree to it. They are written
|
|
115
|
+
out so you can steer the conversation, not because you have to enforce them.
|
|
116
|
+
|
|
83
117
|
**All times in the store's records are EST, 24-hour.** "02:30:00" is 2:30 in
|
|
84
118
|
the morning.
|
|
85
119
|
|
|
86
120
|
**Cancelling a pending order.** Only an order whose status is exactly
|
|
87
|
-
"pending".
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
121
|
+
"pending". The reason must be either "no longer needed" or "ordered by mistake"
|
|
122
|
+
— if the customer gives another reason, tell them those are the only two we can
|
|
123
|
+
record and ask which fits. A gift-card refund lands immediately; everything else
|
|
124
|
+
takes 5 to 7 business days.
|
|
91
125
|
|
|
92
126
|
**Changing the items in a pending order is once-only and irreversible.** After
|
|
93
127
|
it, the order cannot be cancelled or modified again — not by you, not by
|
|
94
|
-
anyone. So before you
|
|
95
|
-
**every** item they want changed
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
become shoes.
|
|
128
|
+
anyone. So before you stage it: get the customer to confirm they have named
|
|
129
|
+
**every** item they want changed. Ask "is that everything you want to change?"
|
|
130
|
+
explicitly, and only then stage the whole list in one call. An item can only
|
|
131
|
+
become a different option of the same product — a shirt cannot become shoes.
|
|
99
132
|
|
|
100
133
|
**Changing a pending order's payment method.** One method only, and it must be
|
|
101
134
|
different from the current one. A gift card must cover the whole order total.
|
|
@@ -103,11 +136,10 @@ The old method is refunded.
|
|
|
103
136
|
|
|
104
137
|
**Returning a delivered order.** Only "delivered", only once. The refund goes
|
|
105
138
|
to the original payment method or to one of their gift cards — nothing else.
|
|
106
|
-
|
|
107
|
-
back.
|
|
139
|
+
The customer gets an email about sending things back.
|
|
108
140
|
|
|
109
141
|
**Exchanging a delivered order.** Only "delivered", only once. Same-product
|
|
110
|
-
options only.
|
|
142
|
+
options only. Ask them to name every item first, exactly as with modifying a
|
|
111
143
|
pending order. The price difference is charged to or refunded from a payment
|
|
112
144
|
method they choose; a gift card must cover a positive difference. No new order
|
|
113
145
|
is needed.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { retailTool } from "../store.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Drop the staged change and go back to helping.
|
|
6
|
+
*
|
|
7
|
+
* Clears `pending` UNCONDITIONALLY and always sends `SETTLED`, so this is the
|
|
8
|
+
* way out of `awaitingConfirmation` from any state the store could be in — a
|
|
9
|
+
* caller who says no, changes their mind about one item, or wants to talk about
|
|
10
|
+
* something else entirely must never leave the call wedged on a change nobody
|
|
11
|
+
* is going to make.
|
|
12
|
+
*/
|
|
13
|
+
export default retailTool({
|
|
14
|
+
name: "cancel_change",
|
|
15
|
+
when: "serving.awaitingConfirmation",
|
|
16
|
+
send: { type: "SETTLED" },
|
|
17
|
+
description:
|
|
18
|
+
"Drop the change that is waiting, without applying it. Use this when the caller says no, " +
|
|
19
|
+
"hesitates, wants any part of it different, or moves on to something else. Nothing was " +
|
|
20
|
+
"changed, so there is nothing to undo — stage the corrected change afterwards if they want one.",
|
|
21
|
+
inputSchema: z.object({}),
|
|
22
|
+
execute: (_args, state) => {
|
|
23
|
+
const dropped = state.pending;
|
|
24
|
+
state.pending = null;
|
|
25
|
+
return {
|
|
26
|
+
dropped: dropped?.kind ?? null,
|
|
27
|
+
message: dropped
|
|
28
|
+
? `Dropped — nothing was changed. The caller did not agree to: ${dropped.plan.readBack}.`
|
|
29
|
+
: "Nothing was staged, so nothing was dropped.",
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
summary: (_args, result) => `dropped ${result.dropped ?? "nothing"}`,
|
|
33
|
+
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
/** tau2 accepts exactly these two. Anything else is refused. */
|
|
8
|
-
const CANCEL_REASONS = ["no longer needed", "ordered by mistake"] as const;
|
|
3
|
+
import { CANCEL_REASONS, planCancel } from "../cancel.ts";
|
|
4
|
+
import { stageAction } from "../pending.ts";
|
|
5
|
+
import { OrderIdField } from "../resolve.ts";
|
|
6
|
+
import { retailTool, setFocus } from "../store.ts";
|
|
9
7
|
|
|
10
8
|
export default retailTool({
|
|
11
9
|
name: "cancel_pending_order",
|
|
12
10
|
when: "serving",
|
|
11
|
+
send: { type: "STAGED" },
|
|
13
12
|
description:
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
13
|
+
"STAGE a cancellation of a pending order — this does NOT cancel anything. Only an order whose " +
|
|
14
|
+
"status is exactly 'pending' can be cancelled, and the reason must be either 'no longer " +
|
|
15
|
+
"needed' or 'ordered by mistake'. The order, its total and where the refund goes come back as " +
|
|
16
|
+
"a sentence to read to the caller; nothing happens until you hear an explicit yes and call " +
|
|
17
|
+
"confirm_change.",
|
|
18
18
|
inputSchema: z.object({
|
|
19
19
|
order_id: OrderIdField,
|
|
20
20
|
reason: z
|
|
@@ -22,54 +22,10 @@ export default retailTool({
|
|
|
22
22
|
.describe("Either 'no longer needed' or 'ordered by mistake' — no other reason is accepted"),
|
|
23
23
|
}),
|
|
24
24
|
execute: (args, state) => {
|
|
25
|
-
const
|
|
26
|
-
if (isToolFailure(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (isToolFailure(order)) return order;
|
|
30
|
-
setFocus(state, { orderId: order.order_id });
|
|
31
|
-
|
|
32
|
-
if (order.status !== "pending") {
|
|
33
|
-
return {
|
|
34
|
-
error: `Order ${order.order_id} is ${order.status}, and only a pending order can be cancelled.`,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
// The enum makes this unreachable from a well-formed call; it stays because
|
|
38
|
-
// the reason is the one field a caller supplies in free speech.
|
|
39
|
-
if (!CANCEL_REASONS.includes(args.reason)) {
|
|
40
|
-
return {
|
|
41
|
-
error: `'${args.reason}' is not an accepted cancellation reason. It must be 'no longer needed' or 'ordered by mistake'.`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let immediate = false;
|
|
46
|
-
const refunds = order.payment_history
|
|
47
|
-
.filter((payment) => payment.transaction_type === "payment")
|
|
48
|
-
.map((payment) => {
|
|
49
|
-
const credited = creditRefund(user, payment.payment_method_id, payment.amount);
|
|
50
|
-
immediate = immediate || credited.immediate;
|
|
51
|
-
return {
|
|
52
|
-
transaction_type: "refund" as const,
|
|
53
|
-
amount: payment.amount,
|
|
54
|
-
payment_method_id: payment.payment_method_id,
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
order.status = "cancelled";
|
|
59
|
-
order.cancel_reason = args.reason;
|
|
60
|
-
order.payment_history.push(...refunds);
|
|
61
|
-
|
|
62
|
-
const total = refunds.reduce((sum, refund) => sum + refund.amount, 0);
|
|
63
|
-
return {
|
|
64
|
-
order_id: order.order_id,
|
|
65
|
-
status: order.status,
|
|
66
|
-
cancel_reason: order.cancel_reason,
|
|
67
|
-
refunded: total,
|
|
68
|
-
refund_immediate: immediate,
|
|
69
|
-
message: `Order ${order.order_id} is cancelled and $${total.toFixed(2)} is being refunded. ${
|
|
70
|
-
immediate ? REFUND_IMMEDIATE_NOTE : REFUND_DELAY_NOTE
|
|
71
|
-
}`,
|
|
72
|
-
};
|
|
25
|
+
const plan = planCancel(state, args.order_id, args.reason);
|
|
26
|
+
if (isToolFailure(plan)) return plan;
|
|
27
|
+
setFocus(state, { orderId: plan.orderId });
|
|
28
|
+
return stageAction(state, { kind: "cancel_pending_order", plan });
|
|
73
29
|
},
|
|
74
|
-
summary: (_args, result) => `
|
|
30
|
+
summary: (_args, result) => `staged: ${result.read_back}`,
|
|
75
31
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { applyAction } from "../pending.ts";
|
|
3
|
+
import { retailTool } from "../store.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The only tool in this template that writes to the store.
|
|
7
|
+
*
|
|
8
|
+
* Gated on `serving.awaitingConfirmation`, which is reachable only by staging a
|
|
9
|
+
* change — so "confirm what nobody staged" is refused by the SDK before this
|
|
10
|
+
* body runs, and the refusal quotes the state's own instruction. See
|
|
11
|
+
* `pending.ts`.
|
|
12
|
+
*/
|
|
13
|
+
export default retailTool({
|
|
14
|
+
name: "confirm_change",
|
|
15
|
+
when: "serving.awaitingConfirmation",
|
|
16
|
+
send: { type: "SETTLED" },
|
|
17
|
+
description:
|
|
18
|
+
"Apply the change that is waiting, after you have read it back to the caller and heard an " +
|
|
19
|
+
"explicit yes. Never call this on an implied yes, on silence, or before you have said what " +
|
|
20
|
+
"the change is. If they say no, or want any part of it different, call cancel_change instead.",
|
|
21
|
+
inputSchema: z.object({}),
|
|
22
|
+
execute: (_args, state) => {
|
|
23
|
+
const action = state.pending;
|
|
24
|
+
// Unreachable while the gate holds: `awaitingConfirmation` is entered only
|
|
25
|
+
// by a staging tool, which writes `pending` in the same synchronous window
|
|
26
|
+
// it sends `STAGED` in. Kept and reported rather than thrown for the reason
|
|
27
|
+
// `authenticatedUser` keeps its own — this runs mid-call, and a sentence
|
|
28
|
+
// the model can act on beats an exception. `cancel_change` is the way out
|
|
29
|
+
// if it ever did fire, which is why that tool clears unconditionally.
|
|
30
|
+
if (!action) {
|
|
31
|
+
return {
|
|
32
|
+
error:
|
|
33
|
+
"Nothing is staged, so there is nothing to confirm. Stage the change again with the " +
|
|
34
|
+
"tool for it, read it back, and confirm once the caller says yes.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const result = applyAction(state, action);
|
|
38
|
+
state.pending = null;
|
|
39
|
+
return { confirmed: action.kind, ...result };
|
|
40
|
+
},
|
|
41
|
+
summary: (_args, result) => `confirmed ${result.confirmed}`,
|
|
42
|
+
});
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { stageAction } from "../pending.ts";
|
|
4
|
+
import { OrderIdField } from "../resolve.ts";
|
|
5
|
+
import { retailTool, setFocus } from "../store.ts";
|
|
6
|
+
import { planExchange } from "../swap.ts";
|
|
6
7
|
|
|
7
8
|
export default retailTool({
|
|
8
9
|
name: "exchange_delivered_order_items",
|
|
9
10
|
when: "serving",
|
|
11
|
+
send: { type: "STAGED" },
|
|
10
12
|
description:
|
|
11
|
-
"
|
|
12
|
-
"Only a 'delivered' order can be exchanged, and only once
|
|
13
|
-
"item they want exchanged before you call this
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"STAGE an exchange of items in a delivered order for different options of the SAME products — " +
|
|
14
|
+
"this does NOT request anything. Only a 'delivered' order can be exchanged, and only once, so " +
|
|
15
|
+
"remind the caller to name EVERY item they want exchanged before you call this. The whole " +
|
|
16
|
+
"list and the price difference come back as a sentence to read to them; nothing happens until " +
|
|
17
|
+
"you hear an explicit yes and call confirm_change. No new order is needed — the customer gets " +
|
|
18
|
+
"an email explaining how to send the originals back.",
|
|
16
19
|
inputSchema: z.object({
|
|
17
20
|
order_id: OrderIdField,
|
|
18
21
|
item_ids: z
|
|
@@ -29,64 +32,16 @@ export default retailTool({
|
|
|
29
32
|
.describe("Method to charge or refund the price difference"),
|
|
30
33
|
}),
|
|
31
34
|
execute: (args, state) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (order.status !== "delivered") {
|
|
40
|
-
return {
|
|
41
|
-
error: `Order ${order.order_id} is ${order.status}. Only a delivered order can be exchanged, and only once.`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// requireDifferent is false: tau2 permits a same-item entry here, and a
|
|
46
|
-
// zero-difference exchange is harmless on a delivered order.
|
|
47
|
-
const plan = planItemSwap(state, order, args.item_ids, args.new_item_ids, {
|
|
48
|
-
requireDifferent: false,
|
|
49
|
-
});
|
|
35
|
+
const plan = planExchange(
|
|
36
|
+
state,
|
|
37
|
+
args.order_id,
|
|
38
|
+
args.item_ids,
|
|
39
|
+
args.new_item_ids,
|
|
40
|
+
args.payment_method_id,
|
|
41
|
+
);
|
|
50
42
|
if (isToolFailure(plan)) return plan;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (blocked) return blocked;
|
|
54
|
-
|
|
55
|
-
// No balance moves and no items change: this records a REQUEST. The money
|
|
56
|
-
// and the item swap settle when the originals come back.
|
|
57
|
-
order.status = "exchange requested";
|
|
58
|
-
// SORTED INDEPENDENTLY, verbatim from tau2 (`order.exchange_items =
|
|
59
|
-
// sorted(item_ids)` / `sorted(new_item_ids)`, the same shape
|
|
60
|
-
// `return_delivered_order_items` uses one list of) — kept because
|
|
61
|
-
// `seed.json` is tau2's data and these fields are what a tau2 task's
|
|
62
|
-
// expected end state is compared against. They are therefore two SETS of
|
|
63
|
-
// ids, not a pairing: sorting each list separately permutes the second
|
|
64
|
-
// against the first whenever the caller named more than one item.
|
|
65
|
-
//
|
|
66
|
-
// Which is why the ANSWER carries `exchanges` instead. `planItemSwap`
|
|
67
|
-
// priced this positionally, so returning the two sorted lists as if they
|
|
68
|
-
// lined up told the caller a pairing the quote was not for — the one thing
|
|
69
|
-
// this result must not do, since the model reads it back down a phone.
|
|
70
|
-
order.exchange_items = [...args.item_ids].sort();
|
|
71
|
-
order.exchange_new_items = [...args.new_item_ids].sort();
|
|
72
|
-
order.exchange_payment_method_id = args.payment_method_id;
|
|
73
|
-
order.exchange_price_difference = plan.diff;
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
order_id: order.order_id,
|
|
77
|
-
status: order.status,
|
|
78
|
-
price_difference: plan.diff,
|
|
79
|
-
// The pairing AS PRICED, per line, in the order the caller gave it.
|
|
80
|
-
exchanges: plan.pairs.map((pair) => ({
|
|
81
|
-
item_id: pair.item.item_id,
|
|
82
|
-
new_item_id: pair.newVariant.item_id,
|
|
83
|
-
price_difference: money(pair.newVariant.price - pair.item.price),
|
|
84
|
-
})),
|
|
85
|
-
message:
|
|
86
|
-
plan.diff > 0
|
|
87
|
-
? `Exchange requested on ${order.order_id}. $${plan.diff.toFixed(2)} will be charged to ${args.payment_method_id}. An email with return instructions is on its way.`
|
|
88
|
-
: `Exchange requested on ${order.order_id}. $${Math.abs(plan.diff).toFixed(2)} will be refunded to ${args.payment_method_id}. An email with return instructions is on its way.`,
|
|
89
|
-
};
|
|
43
|
+
setFocus(state, { orderId: plan.orderId });
|
|
44
|
+
return stageAction(state, { kind: "exchange_delivered_order_items", plan });
|
|
90
45
|
},
|
|
91
|
-
summary: (_args, result) => `
|
|
46
|
+
summary: (_args, result) => `staged: ${result.read_back}`,
|
|
92
47
|
});
|
|
@@ -1,39 +1,27 @@
|
|
|
1
1
|
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { AddressFields,
|
|
4
|
-
import {
|
|
3
|
+
import { AddressFields, planOrderAddress } from "../address.ts";
|
|
4
|
+
import { stageAction } from "../pending.ts";
|
|
5
|
+
import { OrderIdField } from "../resolve.ts";
|
|
5
6
|
import { retailTool, setFocus } from "../store.ts";
|
|
6
7
|
|
|
7
8
|
export default retailTool({
|
|
8
9
|
name: "modify_pending_order_address",
|
|
9
10
|
when: "serving",
|
|
11
|
+
send: { type: "STAGED" },
|
|
10
12
|
description:
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
+
"STAGE a change to a pending order's shipping address — this does NOT change it. The new " +
|
|
14
|
+
"address comes back as a sentence to read to the caller; nothing happens until you hear an " +
|
|
15
|
+
"explicit yes and call confirm_change. This does not touch the customer's default address.",
|
|
13
16
|
inputSchema: z.object({
|
|
14
17
|
order_id: OrderIdField,
|
|
15
18
|
...AddressFields,
|
|
16
19
|
}),
|
|
17
20
|
execute: (args, state) => {
|
|
18
|
-
const
|
|
19
|
-
if (isToolFailure(
|
|
20
|
-
setFocus(state, { orderId:
|
|
21
|
-
|
|
22
|
-
// Any pending variant is fine here — unlike cancel and modify-items, which
|
|
23
|
-
// require exactly 'pending'. Re-addressing a modified order is harmless.
|
|
24
|
-
if (!order.status.startsWith("pending")) {
|
|
25
|
-
return {
|
|
26
|
-
error: `Order ${order.order_id} is ${order.status}, and only a pending order's address can be changed.`,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
order.address = toAddress(args);
|
|
31
|
-
return {
|
|
32
|
-
order_id: order.order_id,
|
|
33
|
-
status: order.status,
|
|
34
|
-
address: order.address,
|
|
35
|
-
message: `Order ${order.order_id} now ships to ${formatAddress(order.address)}.`,
|
|
36
|
-
};
|
|
21
|
+
const plan = planOrderAddress(state, args.order_id, args);
|
|
22
|
+
if (isToolFailure(plan)) return plan;
|
|
23
|
+
setFocus(state, { orderId: plan.orderId });
|
|
24
|
+
return stageAction(state, { kind: "modify_pending_order_address", plan });
|
|
37
25
|
},
|
|
38
|
-
summary: (_args, result) => `
|
|
26
|
+
summary: (_args, result) => `staged: ${result.read_back}`,
|
|
39
27
|
});
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { stageAction } from "../pending.ts";
|
|
4
|
+
import { OrderIdField } from "../resolve.ts";
|
|
5
|
+
import { retailTool, setFocus } from "../store.ts";
|
|
6
|
+
import { planModifyItems } from "../swap.ts";
|
|
6
7
|
|
|
7
8
|
export default retailTool({
|
|
8
9
|
name: "modify_pending_order_items",
|
|
9
10
|
when: "serving",
|
|
11
|
+
send: { type: "STAGED" },
|
|
10
12
|
description:
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"STAGE a change of items in a pending order to different options of the SAME products — this " +
|
|
14
|
+
"does NOT change anything. It can only ever be done ONCE per order and is irreversible: " +
|
|
15
|
+
"afterwards the order can no longer be cancelled or modified at all. So collect EVERY item " +
|
|
16
|
+
"the caller wants changed into one call — ask them 'is that everything you want to change?' " +
|
|
17
|
+
"explicitly first. The whole list and the price difference come back as a sentence to read " +
|
|
18
|
+
"to them; nothing happens until you hear an explicit yes and call confirm_change. The item " +
|
|
19
|
+
"and replacement lists are positional and must be the same length.",
|
|
16
20
|
inputSchema: z.object({
|
|
17
21
|
order_id: OrderIdField,
|
|
18
22
|
item_ids: z
|
|
@@ -29,58 +33,16 @@ export default retailTool({
|
|
|
29
33
|
.describe("Method to charge or refund the price difference, e.g. 'gift_card_0000000'"),
|
|
30
34
|
}),
|
|
31
35
|
execute: (args, state) => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Exactly 'pending'. A 'pending (item modified)' order has already used its
|
|
40
|
-
// one modification, which is what makes this action terminal.
|
|
41
|
-
if (order.status !== "pending") {
|
|
42
|
-
return {
|
|
43
|
-
error: `Order ${order.order_id} is ${order.status}. Items can only be changed while an order is exactly 'pending', and only once.`,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const plan = planItemSwap(state, order, args.item_ids, args.new_item_ids, {
|
|
48
|
-
requireDifferent: true,
|
|
49
|
-
});
|
|
36
|
+
const plan = planModifyItems(
|
|
37
|
+
state,
|
|
38
|
+
args.order_id,
|
|
39
|
+
args.item_ids,
|
|
40
|
+
args.new_item_ids,
|
|
41
|
+
args.payment_method_id,
|
|
42
|
+
);
|
|
50
43
|
if (isToolFailure(plan)) return plan;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (blocked) return blocked;
|
|
54
|
-
|
|
55
|
-
const method = user.payment_methods[args.payment_method_id];
|
|
56
|
-
if (method && isGiftCard(method)) {
|
|
57
|
-
method.balance = money(method.balance - plan.diff);
|
|
58
|
-
}
|
|
59
|
-
order.payment_history.push({
|
|
60
|
-
transaction_type: plan.diff > 0 ? "payment" : "refund",
|
|
61
|
-
amount: money(Math.abs(plan.diff)),
|
|
62
|
-
payment_method_id: args.payment_method_id,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
applySwap(order, plan);
|
|
66
|
-
order.status = "pending (item modified)";
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
order_id: order.order_id,
|
|
70
|
-
status: order.status,
|
|
71
|
-
price_difference: plan.diff,
|
|
72
|
-
items: order.items.map((item) => ({
|
|
73
|
-
name: item.name,
|
|
74
|
-
item_id: item.item_id,
|
|
75
|
-
options: item.options,
|
|
76
|
-
price: item.price,
|
|
77
|
-
})),
|
|
78
|
-
message:
|
|
79
|
-
plan.diff > 0
|
|
80
|
-
? `Done. $${plan.diff.toFixed(2)} was charged to ${args.payment_method_id}. This order can no longer be modified or cancelled.`
|
|
81
|
-
: `Done. $${Math.abs(plan.diff).toFixed(2)} is being refunded to ${args.payment_method_id}. This order can no longer be modified or cancelled.`,
|
|
82
|
-
};
|
|
44
|
+
setFocus(state, { orderId: plan.orderId });
|
|
45
|
+
return stageAction(state, { kind: "modify_pending_order_items", plan });
|
|
83
46
|
},
|
|
84
|
-
summary: (_args, result) =>
|
|
85
|
-
`modified ${result.order_id} (${result.price_difference >= 0 ? "+" : ""}${result.price_difference})`,
|
|
47
|
+
summary: (_args, result) => `staged: ${result.read_back}`,
|
|
86
48
|
});
|