@alexkroman1/aai-cli 5.4.0 → 5.5.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.
Files changed (68) hide show
  1. package/dist/{_agent-D8zBb3M5.mjs → _agent-DMyOab9_.mjs} +2 -2
  2. package/dist/{_config-D3F9km8X.mjs → _config-5AEqhh-O.mjs} +2 -2
  3. package/dist/{_dev-server-cigzayJe.mjs → _dev-server-vV05Fnki.mjs} +1 -1
  4. package/dist/{_init-_G8l4lh2.mjs → _init-BZ9t_Kz-.mjs} +2 -2
  5. package/dist/{_slug-api-19R5kZ0U.mjs → _slug-api-DaqQJHk8.mjs} +1 -1
  6. package/dist/{_templates-DW9CvuDN.mjs → _templates-Bv8CR800.mjs} +1 -1
  7. package/dist/cli.mjs +28 -11
  8. package/dist/{delete-kSXFLxek.mjs → delete-DXilFBb1.mjs} +1 -1
  9. package/dist/{deploy-C0VLnnJe.mjs → deploy-1eaXcfUw.mjs} +2 -2
  10. package/dist/{dev-2oUsvgRX.mjs → dev-gVNdGFYY.mjs} +1 -1
  11. package/dist/{init-BkW9BuZF.mjs → init-DoU4_txp.mjs} +3 -3
  12. package/dist/login-C59ZHzuO.mjs +109 -0
  13. package/dist/login.d.ts +34 -0
  14. package/dist/scaffold/CLAUDE.md +69 -53
  15. package/dist/scaffold/package.json +3 -3
  16. package/dist/{secret-DOva9OGk.mjs → secret-CGAIAbUx.mjs} +1 -1
  17. package/dist/{storage-vM6HjDZZ.mjs → storage-CnhOayhm.mjs} +1 -1
  18. package/dist/templates/code-interpreter/agent.ts +1 -2
  19. package/dist/templates/dispatch-center/agent.ts +5 -5
  20. package/dist/templates/dispatch-center/client.tsx +7 -2
  21. package/dist/templates/embedded-assets/agent.ts +1 -2
  22. package/dist/templates/health-assistant/agent.ts +1 -2
  23. package/dist/templates/infocom-adventure/agent.ts +4 -6
  24. package/dist/templates/infocom-adventure/client.tsx +5 -5
  25. package/dist/templates/math-buddy/agent.ts +6 -5
  26. package/dist/templates/night-owl/agent.ts +1 -2
  27. package/dist/templates/personal-finance/agent.ts +1 -2
  28. package/dist/templates/pipeline-simple/agent.test.ts +13 -13
  29. package/dist/templates/pipeline-simple/agent.ts +5 -6
  30. package/dist/templates/pizza-ordering/agent.ts +1 -2
  31. package/dist/templates/retail/address.ts +29 -0
  32. package/dist/templates/retail/agent.test.ts +1030 -0
  33. package/dist/templates/retail/agent.ts +71 -0
  34. package/dist/templates/retail/authenticate.ts +34 -0
  35. package/dist/templates/retail/client.tsx +459 -0
  36. package/dist/templates/retail/refund.ts +19 -0
  37. package/dist/templates/retail/registry.test.ts +182 -0
  38. package/dist/templates/retail/resolve.test.ts +158 -0
  39. package/dist/templates/retail/resolve.ts +158 -0
  40. package/dist/templates/retail/seed.json +4260 -0
  41. package/dist/templates/retail/seed.test.ts +224 -0
  42. package/dist/templates/retail/shared.test.ts +192 -0
  43. package/dist/templates/retail/shared.ts +430 -0
  44. package/dist/templates/retail/store.test.ts +256 -0
  45. package/dist/templates/retail/store.ts +243 -0
  46. package/dist/templates/retail/swap.test.ts +186 -0
  47. package/dist/templates/retail/swap.ts +138 -0
  48. package/dist/templates/retail/system-prompt.md +111 -0
  49. package/dist/templates/retail/tools/cancel_pending_order.ts +82 -0
  50. package/dist/templates/retail/tools/exchange_delivered_order_items.ts +83 -0
  51. package/dist/templates/retail/tools/find_user_id_by_email.ts +32 -0
  52. package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +38 -0
  53. package/dist/templates/retail/tools/get_item_details.ts +29 -0
  54. package/dist/templates/retail/tools/get_order_details.ts +41 -0
  55. package/dist/templates/retail/tools/get_product_details.ts +33 -0
  56. package/dist/templates/retail/tools/get_user_details.ts +44 -0
  57. package/dist/templates/retail/tools/list_all_product_types.ts +24 -0
  58. package/dist/templates/retail/tools/modify_pending_order_address.ts +46 -0
  59. package/dist/templates/retail/tools/modify_pending_order_items.ts +102 -0
  60. package/dist/templates/retail/tools/modify_pending_order_payment.ts +103 -0
  61. package/dist/templates/retail/tools/modify_user_address.ts +38 -0
  62. package/dist/templates/retail/tools/return_delivered_order_items.ts +101 -0
  63. package/dist/templates/retail/tools/transfer_to_human_agents.ts +22 -0
  64. package/dist/templates/simple/agent.test.ts +1 -1
  65. package/dist/templates/simple/agent.ts +2 -1
  66. package/dist/templates/solo-rpg/agent.ts +1 -2
  67. package/dist/templates/web-researcher/agent.ts +1 -2
  68. package/package.json +3 -3
@@ -11,15 +11,15 @@
11
11
  "deploy": "aai deploy"
12
12
  },
13
13
  "dependencies": {
14
- "@alexkroman1/aai": "^5.4.0",
15
- "@alexkroman1/aai-ui": "^5.4.0",
14
+ "@alexkroman1/aai": "^5.5.0",
15
+ "@alexkroman1/aai-ui": "^5.5.0",
16
16
  "react": "^19.2.8",
17
17
  "react-dom": "^19.2.8",
18
18
  "tailwindcss": "^4.0.0",
19
19
  "zod": "^4.4.3"
20
20
  },
21
21
  "devDependencies": {
22
- "@alexkroman1/aai-cli": "^5.4.0",
22
+ "@alexkroman1/aai-cli": "^5.5.0",
23
23
  "@tailwindcss/vite": "^4.3.3",
24
24
  "@types/node": "^26.1.1",
25
25
  "@types/react": "^19.2.17",
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as unwrapCancel, n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { t as slugRequest } from "./_slug-api-19R5kZ0U.mjs";
3
+ import { t as slugRequest } from "./_slug-api-DaqQJHk8.mjs";
4
4
  import * as p from "@clack/prompts";
5
5
  import { text } from "node:stream/consumers";
6
6
  //#region secret.ts
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
3
- import { t as slugRequest } from "./_slug-api-19R5kZ0U.mjs";
3
+ import { t as slugRequest } from "./_slug-api-DaqQJHk8.mjs";
4
4
  import * as p from "@clack/prompts";
5
5
  //#region storage.ts
6
6
  async function storageRequest(cwd, init, server) {
@@ -1,9 +1,8 @@
1
- import { agent, assemblyAIPipeline } from "@alexkroman1/aai";
1
+ import { agent } from "@alexkroman1/aai";
2
2
  import systemPrompt from "./system-prompt.md?raw";
3
3
 
4
4
  export default agent({
5
5
  name: "Coda",
6
- ...assemblyAIPipeline(),
7
6
  systemPrompt,
8
7
  greeting:
9
8
  "Hey, I'm Coda. I solve problems by writing and running code. Try asking me something like, what's the 50th fibonacci number, or what day of the week was January 1st 2000.",
@@ -1,4 +1,4 @@
1
- import { agent, assemblyAIPipeline } from "@alexkroman1/aai";
1
+ import { agent } from "@alexkroman1/aai";
2
2
  import { assemblyAIStt } from "@alexkroman1/aai/stt";
3
3
  import { dashboardView } from "./shared.ts";
4
4
  import systemPrompt from "./system-prompt.md?raw";
@@ -17,13 +17,13 @@ import { resourcesUpdateStatus } from "./tools/resources_update_status.ts";
17
17
 
18
18
  export default agent({
19
19
  name: "Dispatch Command Center",
20
- ...assemblyAIPipeline(),
21
20
  // One projection replaces eleven `ctx.send("incidents", ...)` calls, and
22
21
  // is the single place that decides caller PII stays server-side.
23
22
  syncState: dashboardView,
24
- // Overriding the STT stage: a dispatcher reads addresses and unit numbers
25
- // in bursts with pauses inside one message, so end-of-turn silence has to
26
- // be longer than the default or "unit twelve … respond to" splits in two.
23
+ // Only the STT stage is declared (LLM and TTS stay on the AssemblyAI
24
+ // defaults): a dispatcher reads addresses and unit numbers in bursts with
25
+ // pauses inside one message, so end-of-turn silence has to be longer than
26
+ // the default or "unit twelve … respond to" splits in two.
27
27
  stt: assemblyAIStt({ minTurnSilenceMs: 2200 }),
28
28
  systemPrompt,
29
29
  greeting:
@@ -300,13 +300,18 @@ function App() {
300
300
  >
301
301
  {session.running ? "Pause" : "Resume"}
302
302
  </button>
303
+ {/* end() hangs up and flips `started` back, so the UI
304
+ returns to "Start Dispatch" and the next start is a
305
+ brand-new shift (fresh incident board, greeting
306
+ included). reset() would keep the call live — the
307
+ buttons never toggle back. */}
303
308
  <button
304
309
  type="button"
305
310
  className="px-4 py-2 border-none rounded-md font-mono text-xs font-semibold uppercase tracking-wider cursor-pointer text-white"
306
311
  style={{ background: "#dc2626" }}
307
- onClick={() => session.reset()}
312
+ onClick={() => session.end()}
308
313
  >
309
- Reset
314
+ End Shift
310
315
  </button>
311
316
  </>
312
317
  )}
@@ -1,4 +1,4 @@
1
- import { agent, assemblyAIPipeline, tool } from "@alexkroman1/aai";
1
+ import { agent, tool } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import knowledge from "./knowledge.json" with { type: "json" };
4
4
 
@@ -14,7 +14,6 @@ const searchable = faqs.map((entry) => ({
14
14
 
15
15
  export default agent({
16
16
  name: "FAQ Bot",
17
- ...assemblyAIPipeline(),
18
17
  systemPrompt:
19
18
  "You are a friendly FAQ assistant. Answer questions using ONLY the information from your embedded knowledge base. If the user asks something not covered by your knowledge base, say you don't have that information and suggest they check the official documentation.\n\nRules:\n- Keep answers concise and conversational — this is a voice agent\n- Quote the knowledge base accurately, do not embellish\n- If a question is ambiguous, ask the user to clarify\n- Use 'search_knowledge' to find answers to specific questions\n- Use 'list_topics' to see all available FAQ topics\n- Always be helpful and polite",
20
19
  greeting:
@@ -1,4 +1,4 @@
1
- import { agent, assemblyAIPipeline, tool } from "@alexkroman1/aai";
1
+ import { agent, tool } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import systemPrompt from "./system-prompt.md?raw";
4
4
 
@@ -76,7 +76,6 @@ function excerptAround(text: string, alias: string): string {
76
76
 
77
77
  export default agent({
78
78
  name: "Dr. Sage",
79
- ...assemblyAIPipeline(),
80
79
  systemPrompt,
81
80
  greeting:
82
81
  "Hey, I'm Dr. Sage. Try asking me something like, what are the side effects of ibuprofen, can I take aspirin and warfarin together, or calculate my BMI. Just remember, I'm not a real doctor, so always check with your healthcare provider.",
@@ -1,15 +1,13 @@
1
- import { agent, assemblyAIPipeline, tool } from "@alexkroman1/aai";
2
- import { assemblyAITts } from "@alexkroman1/aai/tts";
1
+ import { agent, tool } from "@alexkroman1/aai";
3
2
  import { z } from "zod";
4
3
  import { getGameState, resetGameState } from "./shared.ts";
5
4
  import systemPrompt from "./system-prompt.md?raw";
6
5
 
7
6
  export default agent({
8
7
  name: "Cavern Adventure",
9
- ...assemblyAIPipeline(),
10
- // Overriding one stage of the preset: a narrator wants a narrative voice,
11
- // and the other two stages stay as the preset set them.
12
- tts: assemblyAITts({ voice: "paul" }),
8
+ // A narrator wants a narrative voice; everything else stays on the
9
+ // default all-AssemblyAI pipeline.
10
+ voice: "paul",
13
11
  systemPrompt,
14
12
  // The opening scene here must agree with DEFAULT_GAME_STATE.currentRoom
15
13
  // (shared.ts) and the world map in system-prompt.md.
@@ -241,15 +241,15 @@ function InfocomAdventure() {
241
241
  >
242
242
  {session.running ? "[P]ause" : "[R]esume"}
243
243
  </button>
244
- {/* Full reload = new WebSocket = fresh sessionId, so the
245
- session-scoped game state starts over too.
246
- (session.reset() keeps the same sessionId and would
247
- resume the old game.) */}
244
+ {/* end() hangs up and drops the sessionId, so the
245
+ session-scoped game state starts over and the title
246
+ screen returns. (session.reset() keeps the same
247
+ sessionId and would resume the old game.) */}
248
248
  <button
249
249
  type="button"
250
250
  className="px-4 py-1 bg-transparent cursor-pointer uppercase tracking-wider font-mono text-[11px]"
251
251
  style={{ color: GREEN_DIM, border: `1px solid ${GREEN_DARK}` }}
252
- onClick={() => window.location.reload()}
252
+ onClick={() => session.end()}
253
253
  >
254
254
  [N]ew Game
255
255
  </button>
@@ -1,13 +1,14 @@
1
- import { agent, assemblyAIPipeline } from "@alexkroman1/aai";
1
+ import { agent } from "@alexkroman1/aai";
2
2
  import { assemblyAILlm } from "@alexkroman1/aai/llm";
3
3
  import systemPrompt from "./system-prompt.md?raw";
4
4
 
5
5
  export default agent({
6
6
  name: "Math Buddy",
7
- ...assemblyAIPipeline(),
8
- // Overriding the LLM stage: this tutor delegates every calculation to
9
- // run_code, so it needs turn-taking speed more than reasoning depth
10
- // and Flash-Lite is both quicker and cheaper than the preset's default.
7
+ // Only the LLM stage is declared: this tutor delegates every calculation
8
+ // to run_code, so it needs turn-taking speed more than reasoning depth —
9
+ // and Flash-Lite is both quicker and cheaper than the default model. STT
10
+ // and TTS stay on the AssemblyAI defaults. (The string shorthand
11
+ // `llm: "gemini-2.5-flash-lite"` desugars to this same descriptor.)
11
12
  llm: assemblyAILlm({ model: "gemini-2.5-flash-lite" }),
12
13
  systemPrompt,
13
14
  greeting:
@@ -1,4 +1,4 @@
1
- import { agent, assemblyAIPipeline, tool } from "@alexkroman1/aai";
1
+ import { agent, tool } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import { CATEGORIES, type Category, MOODS, type Mood } from "./shared.ts";
4
4
 
@@ -48,7 +48,6 @@ const PICKS: Record<Category, Record<Mood, string[]>> = {
48
48
 
49
49
  export default agent({
50
50
  name: "Night Owl",
51
- ...assemblyAIPipeline(),
52
51
  systemPrompt:
53
52
  "You are Night Owl, a cozy evening companion. You help people wind down, recommend entertainment, and share interesting facts about the night sky. Keep your tone warm and relaxed. Use short, conversational responses.\n\nUse run_code for sleep calculations:\n- Each sleep cycle is 90 minutes, plus 15 minutes to fall asleep\n- Bedtime = wake_time - (cycles * 90 + 15) minutes\n- If result is negative, add 1440 (24 hours in minutes)\n- Format as HH:MM",
54
53
  greeting:
@@ -1,9 +1,8 @@
1
- import { agent, assemblyAIPipeline } from "@alexkroman1/aai";
1
+ import { agent } from "@alexkroman1/aai";
2
2
  import systemPrompt from "./system-prompt.md?raw";
3
3
 
4
4
  export default agent({
5
5
  name: "Penny",
6
- ...assemblyAIPipeline(),
7
6
  systemPrompt,
8
7
  greeting:
9
8
  "Hey, I'm Penny, your personal finance helper. Try asking me something like, what's 100 dollars in euros, what's the price of bitcoin, or help me split a 120 dollar bill four ways with 20 percent tip.",
@@ -4,29 +4,29 @@ import agentDef from "./agent.ts";
4
4
 
5
5
  describe("pipeline-simple template", () => {
6
6
  test("config passes manifest validation", () => {
7
- // Same conversion `aai build`/`aai deploy` run — catches a partial
8
- // provider triple or invalid tuning, not just descriptor presence.
7
+ // Same conversion `aai build`/`aai deploy` run — catches an invalid
8
+ // provider combination or tuning, not just descriptor presence.
9
9
  expect(() => toAgentConfig(agentDef)).not.toThrow();
10
10
  });
11
11
 
12
- test("exports an agent with all three pipeline providers", () => {
13
- // Presence of stt + llm + tts is what flips the runtime into
14
- // pipeline mode (see parseManifest). Smoke-test each is wired up.
12
+ test("declares only the LLM stage on the def", () => {
13
+ // The template's point: swap one stage, leave the rest unset. The
14
+ // unset stages are filled with the AssemblyAI defaults at parse time.
15
15
  expect(agentDef.name).toBe("pipeline-simple");
16
- expect(agentDef.stt).toBeDefined();
17
16
  expect(agentDef.llm).toBeDefined();
18
- expect(agentDef.tts).toBeDefined();
19
- });
20
-
21
- test("STT descriptor is AssemblyAI", () => {
22
- expect(agentDef.stt?.kind).toBe("assemblyai");
17
+ expect(agentDef.stt).toBeUndefined();
18
+ expect(agentDef.tts).toBeUndefined();
23
19
  });
24
20
 
25
21
  test("LLM descriptor is Anthropic", () => {
26
22
  expect(agentDef.llm?.kind).toBe("anthropic");
27
23
  });
28
24
 
29
- test("TTS descriptor is AssemblyAI", () => {
30
- expect(agentDef.tts?.kind).toBe("assemblyai");
25
+ test("unset stages fill to AssemblyAI in the deployable config", () => {
26
+ const config = toAgentConfig(agentDef);
27
+ expect(config.mode).toBe("pipeline");
28
+ expect(config.stt?.kind).toBe("assemblyai");
29
+ expect(config.tts?.kind).toBe("assemblyai");
30
+ expect(config.llm?.kind).toBe("anthropic");
31
31
  });
32
32
  });
@@ -1,13 +1,12 @@
1
- import { agent, assemblyAIPipeline } from "@alexkroman1/aai";
1
+ import { agent } from "@alexkroman1/aai";
2
2
  import { anthropic } from "@alexkroman1/aai/llm";
3
3
 
4
4
  export default agent({
5
5
  name: "pipeline-simple",
6
6
  greeting: "Hi! I'm running in pipeline mode. What can I help with?",
7
- // The preset fills all three stages with AssemblyAI, billed to the one key
8
- // a published agent is guaranteed to have. Spread it, then override the one
9
- // stage you want elsewhere here the LLM. Anything not overridden stays
10
- // AssemblyAI, so swapping a stage never means restating the other two.
11
- ...assemblyAIPipeline(),
7
+ // Declare only the stage you want elsewhere here the LLM. Every stage
8
+ // left unset (STT and TTS here) runs on the AssemblyAI default, billed to
9
+ // the one key a published agent is guaranteed to have, so swapping a stage
10
+ // never means restating the other two.
12
11
  llm: anthropic({ model: "claude-haiku-4-5" }),
13
12
  });
@@ -1,4 +1,4 @@
1
- import { agent, assemblyAIPipeline, tool } from "@alexkroman1/aai";
1
+ import { agent, tool } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import {
4
4
  CRUSTS,
@@ -21,7 +21,6 @@ const crusts = z.enum(CRUSTS);
21
21
 
22
22
  export default agent({
23
23
  name: "Pizza Palace",
24
- ...assemblyAIPipeline(),
25
24
  // The cart, pushed to the client after every tool call. Replaces a
26
25
  // `ctx.send("order", ...)` in each of the five order tools, and the
27
26
  // event-diffing the client had to do to rebuild the cart from them.
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { Address } from "./shared.ts";
3
+
4
+ /** Spread into both address tools' schemas. Two hand-copied zod shapes is how
5
+ * the order address and the profile address drift apart. */
6
+ export const AddressFields = {
7
+ address1: z.string().max(200).describe("First line, e.g. '123 Main St'"),
8
+ address2: z.string().max(200).describe("Second line, e.g. 'Apt 1' — pass '' if there is none"),
9
+ city: z.string().max(100).describe("City, e.g. 'San Francisco'"),
10
+ state: z.string().max(60).describe("State, e.g. 'CA'"),
11
+ country: z.string().max(60).describe("Country, e.g. 'USA'"),
12
+ zip: z.string().max(20).describe("Zip code, e.g. '12345'"),
13
+ };
14
+
15
+ export function toAddress(args: Address): Address {
16
+ return {
17
+ address1: args.address1,
18
+ address2: args.address2,
19
+ city: args.city,
20
+ state: args.state,
21
+ country: args.country,
22
+ zip: args.zip,
23
+ };
24
+ }
25
+
26
+ export function formatAddress(address: Address): string {
27
+ const lines = [address.address1, address.address2].filter(Boolean).join(", ");
28
+ return `${lines}, ${address.city} ${address.state} ${address.zip}, ${address.country}`;
29
+ }