@alexkroman1/aai-cli 5.3.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.
- package/README.md +51 -0
- package/dist/{_agent-D8zBb3M5.mjs → _agent-DMyOab9_.mjs} +2 -2
- package/dist/{_bundler-DFS4xxqE.mjs → _bundler-Cjaxa2wi.mjs} +1 -1
- package/dist/{_config-D3F9km8X.mjs → _config-5AEqhh-O.mjs} +2 -2
- package/dist/{_dev-server-BBUWo0sb.mjs → _dev-server-vV05Fnki.mjs} +3 -3
- package/dist/{_init-DU-sXH6S.mjs → _init-BZ9t_Kz-.mjs} +3 -56
- package/dist/{_slug-api-19R5kZ0U.mjs → _slug-api-DaqQJHk8.mjs} +1 -1
- package/dist/_templates-Bv8CR800.mjs +69 -0
- package/dist/_templates.d.ts +6 -0
- package/dist/{build-Xq1xxoSg.mjs → build-D_PgQOD4.mjs} +1 -1
- package/dist/cli.mjs +59 -17
- package/dist/{client-bundler-BWDkUeEP.mjs → client-bundler-yiWoXrgb.mjs} +3 -0
- package/dist/client-bundler.d.ts +9 -0
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-kSXFLxek.mjs → delete-DXilFBb1.mjs} +1 -1
- package/dist/{deploy-Ci0X1gp2.mjs → deploy-1eaXcfUw.mjs} +3 -3
- package/dist/{dev-g7sGt8qX.mjs → dev-gVNdGFYY.mjs} +1 -1
- package/dist/{init-BjeK8crW.mjs → init-DoU4_txp.mjs} +3 -3
- package/dist/login-C59ZHzuO.mjs +109 -0
- package/dist/login.d.ts +34 -0
- package/dist/scaffold/CLAUDE.md +190 -120
- package/dist/scaffold/package.json +3 -3
- package/dist/{secret-DOva9OGk.mjs → secret-CGAIAbUx.mjs} +1 -1
- package/dist/{storage-vM6HjDZZ.mjs → storage-CnhOayhm.mjs} +1 -1
- package/dist/templates/code-interpreter/agent.ts +1 -2
- package/dist/templates/dispatch-center/agent.test.ts +3 -3
- package/dist/templates/dispatch-center/agent.ts +7 -7
- package/dist/templates/dispatch-center/client.tsx +7 -2
- package/dist/templates/dispatch-center/tools/incident_add_note.ts +1 -1
- package/dist/templates/dispatch-center/tools/incident_create.ts +1 -1
- package/dist/templates/dispatch-center/tools/incident_escalate.ts +1 -1
- package/dist/templates/dispatch-center/tools/incident_get.ts +1 -1
- package/dist/templates/dispatch-center/tools/incident_triage.ts +1 -1
- package/dist/templates/dispatch-center/tools/incident_update_status.ts +1 -1
- package/dist/templates/dispatch-center/tools/ops_protocols.ts +1 -1
- package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +1 -1
- package/dist/templates/dispatch-center/tools/resources_dispatch.ts +1 -1
- package/dist/templates/dispatch-center/tools/resources_get_available.ts +1 -1
- package/dist/templates/dispatch-center/tools/resources_update_status.ts +1 -1
- package/dist/templates/embedded-assets/agent.ts +2 -3
- package/dist/templates/health-assistant/agent.ts +3 -4
- package/dist/templates/infocom-adventure/agent.ts +10 -12
- package/dist/templates/infocom-adventure/client.tsx +5 -5
- package/dist/templates/math-buddy/agent.ts +7 -6
- package/dist/templates/night-owl/agent.ts +2 -3
- package/dist/templates/personal-finance/agent.ts +1 -2
- package/dist/templates/pipeline-simple/agent.test.ts +13 -13
- package/dist/templates/pipeline-simple/agent.ts +5 -6
- package/dist/templates/pizza-ordering/agent.test.ts +13 -11
- package/dist/templates/pizza-ordering/agent.ts +5 -6
- package/dist/templates/retail/address.ts +29 -0
- package/dist/templates/retail/agent.test.ts +1030 -0
- package/dist/templates/retail/agent.ts +71 -0
- package/dist/templates/retail/authenticate.ts +34 -0
- package/dist/templates/retail/client.tsx +459 -0
- package/dist/templates/retail/refund.ts +19 -0
- package/dist/templates/retail/registry.test.ts +182 -0
- package/dist/templates/retail/resolve.test.ts +158 -0
- package/dist/templates/retail/resolve.ts +158 -0
- package/dist/templates/retail/seed.json +4260 -0
- package/dist/templates/retail/seed.test.ts +224 -0
- package/dist/templates/retail/shared.test.ts +192 -0
- package/dist/templates/retail/shared.ts +430 -0
- package/dist/templates/retail/store.test.ts +256 -0
- package/dist/templates/retail/store.ts +243 -0
- package/dist/templates/retail/swap.test.ts +186 -0
- package/dist/templates/retail/swap.ts +138 -0
- package/dist/templates/retail/system-prompt.md +111 -0
- package/dist/templates/retail/tools/cancel_pending_order.ts +82 -0
- package/dist/templates/retail/tools/exchange_delivered_order_items.ts +83 -0
- package/dist/templates/retail/tools/find_user_id_by_email.ts +32 -0
- package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +38 -0
- package/dist/templates/retail/tools/get_item_details.ts +29 -0
- package/dist/templates/retail/tools/get_order_details.ts +41 -0
- package/dist/templates/retail/tools/get_product_details.ts +33 -0
- package/dist/templates/retail/tools/get_user_details.ts +44 -0
- package/dist/templates/retail/tools/list_all_product_types.ts +24 -0
- package/dist/templates/retail/tools/modify_pending_order_address.ts +46 -0
- package/dist/templates/retail/tools/modify_pending_order_items.ts +102 -0
- package/dist/templates/retail/tools/modify_pending_order_payment.ts +103 -0
- package/dist/templates/retail/tools/modify_user_address.ts +38 -0
- package/dist/templates/retail/tools/return_delivered_order_items.ts +101 -0
- package/dist/templates/retail/tools/transfer_to_human_agents.ts +22 -0
- package/dist/templates/simple/agent.test.ts +18 -0
- package/dist/templates/simple/agent.ts +3 -0
- package/dist/templates/solo-rpg/agent.test.ts +2 -2
- package/dist/templates/solo-rpg/agent.ts +1 -2
- package/dist/templates/solo-rpg/tools/action_roll.ts +1 -1
- package/dist/templates/solo-rpg/tools/load_game.ts +1 -1
- package/dist/templates/solo-rpg/tools/oracle.ts +1 -1
- package/dist/templates/solo-rpg/tools/save_game.ts +1 -1
- package/dist/templates/solo-rpg/tools/setup_character.ts +1 -1
- package/dist/templates/solo-rpg/tools/update_state.ts +1 -1
- package/dist/templates/web-researcher/agent.ts +1 -2
- package/dist/typecheck.d.ts +18 -0
- package/dist/typecheck.mjs +8 -0
- package/dist/worker-bundler.d.ts +9 -1
- package/dist/worker-bundler.mjs +8 -0
- package/package.json +3 -3
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
"deploy": "aai deploy"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@alexkroman1/aai": "^5.
|
|
15
|
-
"@alexkroman1/aai-ui": "^5.
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
|
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.",
|
|
@@ -90,17 +90,17 @@ describe("dispatch-center template", () => {
|
|
|
90
90
|
|
|
91
91
|
test("negative casualty counts are rejected by the parameter schemas", () => {
|
|
92
92
|
expect(
|
|
93
|
-
incidentTriage.
|
|
93
|
+
incidentTriage.inputSchema?.safeParse({ incidentId: "INC-0001", casualtyUpdate: -5 }).success,
|
|
94
94
|
).toBe(false);
|
|
95
95
|
expect(
|
|
96
|
-
incidentCreate.
|
|
96
|
+
incidentCreate.inputSchema?.safeParse({
|
|
97
97
|
location: "1 First St",
|
|
98
98
|
description: "fire",
|
|
99
99
|
estimatedCasualties: -1,
|
|
100
100
|
}).success,
|
|
101
101
|
).toBe(false);
|
|
102
102
|
expect(
|
|
103
|
-
incidentUpdateStatus.
|
|
103
|
+
incidentUpdateStatus.inputSchema?.safeParse({
|
|
104
104
|
incidentId: "INC-0001",
|
|
105
105
|
status: "on_scene",
|
|
106
106
|
casualtyUpdate: { confirmed: -2 },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { agent
|
|
2
|
-
import {
|
|
1
|
+
import { agent } from "@alexkroman1/aai";
|
|
2
|
+
import { assemblyAIStt } from "@alexkroman1/aai/stt";
|
|
3
3
|
import { dashboardView } from "./shared.ts";
|
|
4
4
|
import systemPrompt from "./system-prompt.md?raw";
|
|
5
5
|
import { incidentAddNote } from "./tools/incident_add_note.ts";
|
|
@@ -17,14 +17,14 @@ 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
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
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
|
+
stt: assemblyAIStt({ minTurnSilenceMs: 2200 }),
|
|
28
28
|
systemPrompt,
|
|
29
29
|
greeting:
|
|
30
30
|
"Dispatch Command Center online. Restoring operational state. I'm ready to take incoming calls, manage active incidents, or run dispatch operations. Say 'dashboard' for a full status report. What do we have.",
|
|
@@ -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.
|
|
312
|
+
onClick={() => session.end()}
|
|
308
313
|
>
|
|
309
|
-
|
|
314
|
+
End Shift
|
|
310
315
|
</button>
|
|
311
316
|
</>
|
|
312
317
|
)}
|
|
@@ -4,7 +4,7 @@ import { findIncident, logEvent, updateState } from "../shared.ts";
|
|
|
4
4
|
|
|
5
5
|
export const incidentAddNote = tool({
|
|
6
6
|
description: "Add a situational update note to an incident's timeline.",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
9
9
|
note: z.string().max(1000).describe("The note to add"),
|
|
10
10
|
source: z.string().max(100).describe("Who reported this — unit callsign or caller").optional(),
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
|
|
14
14
|
export const incidentCreate = tool({
|
|
15
15
|
description: "Create a new incident from an incoming emergency call.",
|
|
16
|
-
|
|
16
|
+
inputSchema: z.object({
|
|
17
17
|
location: z.string().max(300).describe("Address or location description"),
|
|
18
18
|
description: z.string().max(2000).describe("Nature of the emergency as described by caller"),
|
|
19
19
|
callerName: z.string().max(120).describe("Caller's name").optional(),
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
export const incidentEscalate = tool({
|
|
13
13
|
description: "Escalate an incident when it exceeds current capacity or severity increases.",
|
|
14
|
-
|
|
14
|
+
inputSchema: z.object({
|
|
15
15
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
16
16
|
reason: z.string().max(1000).describe("Reason for escalation"),
|
|
17
17
|
requestMutualAid: z
|
|
@@ -4,7 +4,7 @@ import { findIncident, getApplicableProtocols, getState, incidentAgeMinutes } fr
|
|
|
4
4
|
|
|
5
5
|
export const incidentGet = tool({
|
|
6
6
|
description: "Get full details on a specific incident including timeline and assigned resources.",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
9
9
|
}),
|
|
10
10
|
async execute(args, ctx) {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
export const incidentTriage = tool({
|
|
16
16
|
description:
|
|
17
17
|
"Triage an incident — confirm or override severity, type, hazards, and casualty count.",
|
|
18
|
-
|
|
18
|
+
inputSchema: z.object({
|
|
19
19
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
20
20
|
severity: z.enum(SEVERITIES).describe("Confirmed severity after triage").optional(),
|
|
21
21
|
type: z.enum(INCIDENT_TYPES).describe("Confirmed incident type").optional(),
|
|
@@ -4,7 +4,7 @@ import { assertNotResolved, findIncident, logEvent, updateState } from "../share
|
|
|
4
4
|
|
|
5
5
|
export const incidentUpdateStatus = tool({
|
|
6
6
|
description: "Update an incident's status (en_route, on_scene, resolved, escalated).",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
9
9
|
status: z.enum(["en_route", "on_scene", "resolved", "escalated"]).describe("New status"),
|
|
10
10
|
notes: z.string().max(1000).describe("Status update notes").optional(),
|
|
@@ -4,7 +4,7 @@ import { getApplicableProtocols, INCIDENT_TYPES, SEVERITIES } from "../shared.ts
|
|
|
4
4
|
|
|
5
5
|
export const opsProtocols = tool({
|
|
6
6
|
description: "Look up step-by-step response protocols for a given incident type and severity.",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
incidentType: z.enum(INCIDENT_TYPES).describe("Type of incident"),
|
|
9
9
|
severity: z.enum(SEVERITIES).describe("Severity level"),
|
|
10
10
|
}),
|
|
@@ -119,7 +119,7 @@ const SCENARIO_NAMES = Object.keys(scenarios) as [ScenarioName, ...ScenarioName[
|
|
|
119
119
|
|
|
120
120
|
export const opsRunScenario = tool({
|
|
121
121
|
description: "Run a training scenario that creates simulated incidents for dispatch practice.",
|
|
122
|
-
|
|
122
|
+
inputSchema: z.object({
|
|
123
123
|
scenario: z.enum(SCENARIO_NAMES).describe("Scenario type to simulate"),
|
|
124
124
|
}),
|
|
125
125
|
async execute(args, ctx) {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
export const resourcesDispatch = tool({
|
|
13
13
|
description:
|
|
14
14
|
"Dispatch units to an incident. Can auto-dispatch recommended resources or manually specify callsigns.",
|
|
15
|
-
|
|
15
|
+
inputSchema: z.object({
|
|
16
16
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
17
17
|
callsigns: z
|
|
18
18
|
.array(z.string().max(50))
|
|
@@ -4,7 +4,7 @@ import { getState, RESOURCE_TYPES } from "../shared.ts";
|
|
|
4
4
|
|
|
5
5
|
export const resourcesGetAvailable = tool({
|
|
6
6
|
description: "List available resources, optionally filtered by type.",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
type: z
|
|
9
9
|
.enum([...RESOURCE_TYPES, "all"])
|
|
10
10
|
.describe("Filter by resource type, or 'all'")
|
|
@@ -4,7 +4,7 @@ import { logEvent, RESOURCE_STATUSES, updateState } from "../shared.ts";
|
|
|
4
4
|
|
|
5
5
|
export const resourcesUpdateStatus = tool({
|
|
6
6
|
description: "Update a resource unit's status when it radios in.",
|
|
7
|
-
|
|
7
|
+
inputSchema: z.object({
|
|
8
8
|
callsign: z.string().max(50).describe("The resource callsign"),
|
|
9
9
|
status: z.enum(RESOURCE_STATUSES).describe("New status"),
|
|
10
10
|
notes: z.string().max(1000).describe("Status notes").optional(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { agent,
|
|
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:
|
|
@@ -31,7 +30,7 @@ export default agent({
|
|
|
31
30
|
search_knowledge: tool({
|
|
32
31
|
description:
|
|
33
32
|
"Search the embedded FAQ knowledge base for an answer matching the user's question.",
|
|
34
|
-
|
|
33
|
+
inputSchema: z.object({
|
|
35
34
|
query: z.string().describe("The user's question to search for"),
|
|
36
35
|
}),
|
|
37
36
|
async execute(args) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { agent,
|
|
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.",
|
|
@@ -86,7 +85,7 @@ export default agent({
|
|
|
86
85
|
check_drug_interaction: tool({
|
|
87
86
|
description:
|
|
88
87
|
"Check for interactions between two or more medications using FDA drug label data. Looks up each drug's official label and reports where one drug's Drug Interactions section mentions another. Absence of a mention does not guarantee safety.",
|
|
89
|
-
|
|
88
|
+
inputSchema: z.object({
|
|
90
89
|
drugs: z
|
|
91
90
|
.array(z.string().min(1))
|
|
92
91
|
.min(2)
|
|
@@ -142,7 +141,7 @@ export default agent({
|
|
|
142
141
|
medication_lookup: tool({
|
|
143
142
|
description:
|
|
144
143
|
"Look up detailed information about a single medication, including purpose, warnings, dosage, side effects, and manufacturer. Works with both generic and brand names.",
|
|
145
|
-
|
|
144
|
+
inputSchema: z.object({
|
|
146
145
|
name: z
|
|
147
146
|
.string()
|
|
148
147
|
.describe("Medication name (generic or brand, e.g. 'ibuprofen' or 'Advil')"),
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { agent,
|
|
2
|
-
import { assemblyAI as 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
|
-
|
|
10
|
-
//
|
|
11
|
-
|
|
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.
|
|
@@ -19,7 +17,7 @@ export default agent({
|
|
|
19
17
|
tools: {
|
|
20
18
|
game_state_drop: tool({
|
|
21
19
|
description: "Remove an item from the player's inventory.",
|
|
22
|
-
|
|
20
|
+
inputSchema: z.object({
|
|
23
21
|
value: z.string().describe("Item name to drop"),
|
|
24
22
|
}),
|
|
25
23
|
async execute(args, ctx) {
|
|
@@ -31,7 +29,7 @@ export default agent({
|
|
|
31
29
|
|
|
32
30
|
game_state_flag: tool({
|
|
33
31
|
description: "Set a game flag to true, used for tracking puzzle and event state.",
|
|
34
|
-
|
|
32
|
+
inputSchema: z.object({
|
|
35
33
|
value: z.string().describe("Flag name to set"),
|
|
36
34
|
}),
|
|
37
35
|
async execute(args, ctx) {
|
|
@@ -59,7 +57,7 @@ export default agent({
|
|
|
59
57
|
|
|
60
58
|
game_state_history: tool({
|
|
61
59
|
description: "Log a player command to the history and increment the move counter.",
|
|
62
|
-
|
|
60
|
+
inputSchema: z.object({
|
|
63
61
|
value: z.string().describe("Command text to log"),
|
|
64
62
|
}),
|
|
65
63
|
async execute(args, ctx) {
|
|
@@ -72,7 +70,7 @@ export default agent({
|
|
|
72
70
|
|
|
73
71
|
game_state_move: tool({
|
|
74
72
|
description: "Move the player to a new room and increment the move counter.",
|
|
75
|
-
|
|
73
|
+
inputSchema: z.object({
|
|
76
74
|
value: z.string().describe("Room name to move to"),
|
|
77
75
|
}),
|
|
78
76
|
async execute(args, ctx) {
|
|
@@ -94,7 +92,7 @@ export default agent({
|
|
|
94
92
|
|
|
95
93
|
game_state_score: tool({
|
|
96
94
|
description: "Add points to the player's score.",
|
|
97
|
-
|
|
95
|
+
inputSchema: z.object({
|
|
98
96
|
value: z.number().describe("Points to add"),
|
|
99
97
|
}),
|
|
100
98
|
async execute(args, ctx) {
|
|
@@ -106,7 +104,7 @@ export default agent({
|
|
|
106
104
|
|
|
107
105
|
game_state_take: tool({
|
|
108
106
|
description: "Add an item to the player's inventory.",
|
|
109
|
-
|
|
107
|
+
inputSchema: z.object({
|
|
110
108
|
value: z.string().describe("Item name to take"),
|
|
111
109
|
}),
|
|
112
110
|
async execute(args, ctx) {
|
|
@@ -241,15 +241,15 @@ function InfocomAdventure() {
|
|
|
241
241
|
>
|
|
242
242
|
{session.running ? "[P]ause" : "[R]esume"}
|
|
243
243
|
</button>
|
|
244
|
-
{/*
|
|
245
|
-
session-scoped game state starts over
|
|
246
|
-
(session.reset() keeps the same
|
|
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={() =>
|
|
252
|
+
onClick={() => session.end()}
|
|
253
253
|
>
|
|
254
254
|
[N]ew Game
|
|
255
255
|
</button>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { agent
|
|
2
|
-
import {
|
|
1
|
+
import { agent } from "@alexkroman1/aai";
|
|
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
|
-
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// and
|
|
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,
|
|
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:
|
|
@@ -58,7 +57,7 @@ export default agent({
|
|
|
58
57
|
tools: {
|
|
59
58
|
recommend: tool({
|
|
60
59
|
description: "Get recommendations for movies, music, or books based on mood.",
|
|
61
|
-
|
|
60
|
+
inputSchema: z.object({
|
|
62
61
|
category: z.enum(CATEGORIES),
|
|
63
62
|
mood: z.enum(MOODS),
|
|
64
63
|
}),
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { agent
|
|
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
|
|
8
|
-
// provider
|
|
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("
|
|
13
|
-
//
|
|
14
|
-
//
|
|
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.
|
|
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("
|
|
30
|
-
|
|
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
|
|
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
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
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
|
});
|
|
@@ -76,17 +76,19 @@ describe("pricing (shared.ts)", () => {
|
|
|
76
76
|
expect(calculateTotal([a, b])).toBeCloseTo(8.99 * 4, 5);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
test("add_pizza schema defaults quantity to 1 and rejects non-positive quantities", () => {
|
|
80
|
-
const schema = getTool("add_pizza").
|
|
81
|
-
if (!schema) throw new Error("add_pizza has no
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
87
|
-
expect(()
|
|
88
|
-
|
|
89
|
-
).
|
|
79
|
+
test("add_pizza schema defaults quantity to 1 and rejects non-positive quantities", async () => {
|
|
80
|
+
const schema = getTool("add_pizza").inputSchema;
|
|
81
|
+
if (!schema) throw new Error("add_pizza has no input schema");
|
|
82
|
+
// Validate through the Standard Schema contract — the vendor-neutral
|
|
83
|
+
// interface every inputSchema carries.
|
|
84
|
+
const validate = (value: unknown) => schema["~standard"].validate(value);
|
|
85
|
+
const ok = await validate({ size: "small", crust: "thin", toppings: [] });
|
|
86
|
+
if (ok.issues) throw new Error("expected valid input");
|
|
87
|
+
expect((ok.value as { quantity: number }).quantity).toBe(1);
|
|
88
|
+
const zero = await validate({ size: "small", crust: "thin", toppings: [], quantity: 0 });
|
|
89
|
+
expect(zero.issues).toBeDefined();
|
|
90
|
+
const frac = await validate({ size: "small", crust: "thin", toppings: [], quantity: 1.5 });
|
|
91
|
+
expect(frac.issues).toBeDefined();
|
|
90
92
|
});
|
|
91
93
|
});
|
|
92
94
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { agent,
|
|
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.
|
|
@@ -35,7 +34,7 @@ export default agent({
|
|
|
35
34
|
tools: {
|
|
36
35
|
add_pizza: tool({
|
|
37
36
|
description: "Add a pizza to the order. Use when the customer has decided on a pizza.",
|
|
38
|
-
|
|
37
|
+
inputSchema: z.object({
|
|
39
38
|
size: sizes,
|
|
40
39
|
crust: crusts,
|
|
41
40
|
toppings: z
|
|
@@ -93,7 +92,7 @@ export default agent({
|
|
|
93
92
|
|
|
94
93
|
remove_pizza: tool({
|
|
95
94
|
description: "Remove a pizza from the order by its ID.",
|
|
96
|
-
|
|
95
|
+
inputSchema: z.object({
|
|
97
96
|
pizza_id: z.number().describe("The pizza ID to remove"),
|
|
98
97
|
}),
|
|
99
98
|
async execute(args, ctx) {
|
|
@@ -113,7 +112,7 @@ export default agent({
|
|
|
113
112
|
|
|
114
113
|
set_customer_name: tool({
|
|
115
114
|
description: "Set the customer name for the order.",
|
|
116
|
-
|
|
115
|
+
inputSchema: z.object({
|
|
117
116
|
name: z.string(),
|
|
118
117
|
}),
|
|
119
118
|
async execute(args, ctx) {
|
|
@@ -124,7 +123,7 @@ export default agent({
|
|
|
124
123
|
|
|
125
124
|
update_pizza: tool({
|
|
126
125
|
description: "Update an existing pizza in the order. Only provided fields are changed.",
|
|
127
|
-
|
|
126
|
+
inputSchema: z.object({
|
|
128
127
|
pizza_id: z.number(),
|
|
129
128
|
size: sizes.optional(),
|
|
130
129
|
crust: crusts.optional(),
|
|
@@ -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
|
+
}
|