@alexkroman1/aai-cli 5.13.2 → 6.1.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 (236) hide show
  1. package/dist/{_agent-C8Jk-ZcP.mjs → _agent-vGW5SBnX.mjs} +23 -5
  2. package/dist/_agent.d.ts +18 -0
  3. package/dist/{_api-client-BX8Qv51n.mjs → _api-client-LgLksMhN.mjs} +45 -8
  4. package/dist/_api-client.d.ts +39 -0
  5. package/dist/{_bundler-BuIyDdvs.mjs → _bundler-BapCUUJN.mjs} +42 -14
  6. package/dist/_bundler.d.ts +43 -5
  7. package/dist/_cli-common.d.ts +67 -3
  8. package/dist/{_config-CzwAWOWr.mjs → _config-D_s09e7g.mjs} +36 -18
  9. package/dist/_deploy.d.ts +2 -5
  10. package/dist/_dev-restart.d.ts +6 -1
  11. package/dist/{_dev-server-Ch7K8e8i.mjs → _dev-server-DQ1t9sbw.mjs} +94 -38
  12. package/dist/_dev-server.d.ts +30 -2
  13. package/dist/_e2e-test-utils.d.ts +80 -0
  14. package/dist/_fault-mode.d.ts +175 -0
  15. package/dist/{_init-CbkrE2wq.mjs → _init-CpISqoR8.mjs} +3 -3
  16. package/dist/{_output-CC300DzW.mjs → _output-CKkmWs7i.mjs} +8 -1
  17. package/dist/_output.d.ts +9 -2
  18. package/dist/{_server-common-61fL__39.mjs → _server-common-6e0QI4mq.mjs} +1 -1
  19. package/dist/{_slug-api-D30zPmsn.mjs → _slug-api-D2heILuC.mjs} +2 -2
  20. package/dist/{_studio-D2ciIhbi.mjs → _studio-zAJycZ8j.mjs} +3 -3
  21. package/dist/{_templates-B1kt3BGt.mjs → _templates-iDGjGiPf.mjs} +4 -6
  22. package/dist/{_typecheck-gate-4v9UBZHh.mjs → _typecheck-gate-BXvUNnfs.mjs} +1 -1
  23. package/dist/{_utils-0DHbcqUb.mjs → _utils-B8QmtFhK.mjs} +21 -7
  24. package/dist/_utils.d.ts +18 -2
  25. package/dist/{_vite-env-Dg_QlVv0.mjs → _vite-env-BNveawd1.mjs} +31 -1
  26. package/dist/_vite-env.d.ts +30 -0
  27. package/dist/build-BO1Ni6oJ.mjs +62 -0
  28. package/dist/build.d.ts +19 -0
  29. package/dist/cli-workflow.d.ts +10 -0
  30. package/dist/cli.d.ts +1 -2
  31. package/dist/cli.mjs +406 -224
  32. package/dist/{client-bundler-C9qXL8A2.mjs → client-bundler-B8Q9F8gJ.mjs} +3 -22
  33. package/dist/client-bundler.mjs +1 -1
  34. package/dist/{delete-DCRX3d96.mjs → delete-4I0uNR4a.mjs} +6 -7
  35. package/dist/delete.d.ts +2 -8
  36. package/dist/{deploy-DjsEV-40.mjs → deploy-DJ3HRcia.mjs} +13 -14
  37. package/dist/{dev-CvPH5dbF.mjs → dev-C6SWaAZP.mjs} +3 -3
  38. package/dist/{eject-LgBRfnbH.mjs → eject-Zrzk5KV3.mjs} +41 -15
  39. package/dist/eject.d.ts +30 -3
  40. package/dist/{init-BppxMR8r.mjs → init-BTRGiPQr.mjs} +61 -26
  41. package/dist/init.d.ts +11 -0
  42. package/dist/{login-BQQaxJhL.mjs → login-k0Z3VQu9.mjs} +5 -5
  43. package/dist/project-config.mjs +1 -1
  44. package/dist/scaffold/CLAUDE.md +498 -91
  45. package/dist/scaffold/package.json +11 -8
  46. package/dist/scaffold/pnpm-workspace.yaml +32 -0
  47. package/dist/scaffold/server.mjs +53 -57
  48. package/dist/{secret-Ds9dvqAj.mjs → secret-DzSQx1Ds.mjs} +6 -3
  49. package/dist/{storage-DbrQSHFk.mjs → storage-C-Do0mIA.mjs} +18 -6
  50. package/dist/{studio-GSFd4s5O.mjs → studio-BGVmCA2G.mjs} +10 -10
  51. package/dist/templates/code-interpreter/agent.ts +0 -2
  52. package/dist/templates/dispatch-center/agent.test.ts +21 -30
  53. package/dist/templates/dispatch-center/agent.ts +4 -31
  54. package/dist/templates/dispatch-center/client.tsx +41 -28
  55. package/dist/templates/dispatch-center/shared.ts +73 -66
  56. package/dist/templates/dispatch-center/tools/incident_add_note.ts +13 -15
  57. package/dist/templates/dispatch-center/tools/incident_create.ts +42 -45
  58. package/dist/templates/dispatch-center/tools/incident_escalate.ts +60 -62
  59. package/dist/templates/dispatch-center/tools/incident_get.ts +10 -6
  60. package/dist/templates/dispatch-center/tools/incident_triage.ts +44 -46
  61. package/dist/templates/dispatch-center/tools/incident_update_status.ts +40 -42
  62. package/dist/templates/dispatch-center/tools/ops_dashboard.ts +3 -6
  63. package/dist/templates/dispatch-center/tools/ops_protocols.ts +1 -1
  64. package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +21 -24
  65. package/dist/templates/dispatch-center/tools/resources_dispatch.ts +53 -55
  66. package/dist/templates/dispatch-center/tools/resources_get_available.ts +3 -5
  67. package/dist/templates/dispatch-center/tools/resources_update_status.ts +40 -43
  68. package/dist/templates/embedded-assets/agent.test.ts +83 -0
  69. package/dist/templates/embedded-assets/agent.ts +1 -48
  70. package/dist/templates/embedded-assets/shared.ts +17 -0
  71. package/dist/templates/embedded-assets/system-prompt.md +13 -0
  72. package/dist/templates/embedded-assets/tools/list_topics.ts +9 -0
  73. package/dist/templates/embedded-assets/tools/search_knowledge.ts +26 -0
  74. package/dist/templates/health-assistant/agent.test.ts +169 -0
  75. package/dist/templates/health-assistant/agent.ts +1 -166
  76. package/dist/templates/health-assistant/fda.ts +100 -0
  77. package/dist/templates/health-assistant/tools/check_drug_interaction.ts +59 -0
  78. package/dist/templates/health-assistant/tools/medication_lookup.ts +31 -0
  79. package/dist/templates/infocom-adventure/agent.test.ts +205 -0
  80. package/dist/templates/infocom-adventure/agent.ts +3 -106
  81. package/dist/templates/infocom-adventure/client.tsx +32 -28
  82. package/dist/templates/infocom-adventure/shared.ts +36 -16
  83. package/dist/templates/infocom-adventure/tools/game_state_drop.ts +13 -0
  84. package/dist/templates/infocom-adventure/tools/game_state_flag.ts +13 -0
  85. package/dist/templates/infocom-adventure/tools/game_state_get.ts +16 -0
  86. package/dist/templates/infocom-adventure/tools/game_state_history.ts +14 -0
  87. package/dist/templates/infocom-adventure/tools/game_state_move.ts +14 -0
  88. package/dist/templates/infocom-adventure/tools/game_state_restart.ts +13 -0
  89. package/dist/templates/infocom-adventure/tools/game_state_score.ts +13 -0
  90. package/dist/templates/infocom-adventure/tools/game_state_take.ts +13 -0
  91. package/dist/templates/link-digest/agent.test.ts +223 -0
  92. package/dist/templates/link-digest/agent.ts +79 -0
  93. package/dist/templates/link-digest/client.tsx +146 -0
  94. package/dist/templates/link-digest/workflows/digest.ts +248 -0
  95. package/dist/templates/math-buddy/agent.ts +0 -2
  96. package/dist/templates/night-owl/agent.test.ts +80 -0
  97. package/dist/templates/night-owl/agent.ts +1 -68
  98. package/dist/templates/night-owl/system-prompt.md +10 -0
  99. package/dist/templates/night-owl/tools/recommend.ts +64 -0
  100. package/dist/templates/personal-finance/agent.ts +0 -2
  101. package/dist/templates/pizza-ordering/agent.test.ts +59 -58
  102. package/dist/templates/pizza-ordering/agent.ts +10 -159
  103. package/dist/templates/pizza-ordering/client.tsx +4 -4
  104. package/dist/templates/pizza-ordering/shared.ts +44 -27
  105. package/dist/templates/pizza-ordering/tools/add_pizza.ts +31 -0
  106. package/dist/templates/pizza-ordering/tools/place_order.ts +22 -0
  107. package/dist/templates/pizza-ordering/tools/remove_pizza.ts +22 -0
  108. package/dist/templates/pizza-ordering/tools/set_customer_name.ts +13 -0
  109. package/dist/templates/pizza-ordering/tools/update_pizza.ts +28 -0
  110. package/dist/templates/pizza-ordering/tools/view_order.ts +21 -0
  111. package/dist/templates/plan-and-execute/agent.test.ts +411 -0
  112. package/dist/templates/plan-and-execute/agent.ts +23 -0
  113. package/dist/templates/plan-and-execute/client.tsx +115 -0
  114. package/dist/templates/plan-and-execute/graph.ts +178 -0
  115. package/dist/templates/plan-and-execute/prompts.ts +110 -0
  116. package/dist/templates/plan-and-execute/shared.ts +161 -0
  117. package/dist/templates/plan-and-execute/system-prompt.md +18 -0
  118. package/dist/templates/plan-and-execute/tools/plan_status.ts +20 -0
  119. package/dist/templates/plan-and-execute/tools/revise_plan.ts +63 -0
  120. package/dist/templates/plan-and-execute/tools/start_plan.ts +51 -0
  121. package/dist/templates/plan-and-execute/tools/work_next_step.ts +101 -0
  122. package/dist/templates/recap-workflow/agent.test.ts +762 -0
  123. package/dist/templates/recap-workflow/agent.ts +95 -0
  124. package/dist/templates/recap-workflow/shared.ts +43 -0
  125. package/dist/templates/recap-workflow/tools/cancel_recap.ts +23 -0
  126. package/dist/templates/recap-workflow/tools/keep_transcript.ts +31 -0
  127. package/dist/templates/recap-workflow/tools/recap_progress.ts +27 -0
  128. package/dist/templates/recap-workflow/tools/recap_status.ts +46 -0
  129. package/dist/templates/recap-workflow/tools/request_recap.ts +43 -0
  130. package/dist/templates/recap-workflow/workflows/recap.ts +544 -0
  131. package/dist/templates/recap-workflow/workflows/tokens.ts +26 -0
  132. package/dist/templates/redline/agent.test.ts +222 -0
  133. package/dist/templates/redline/agent.ts +89 -0
  134. package/dist/templates/redline/client.tsx +184 -0
  135. package/dist/templates/redline/workflows/prompts.ts +68 -0
  136. package/dist/templates/redline/workflows/redline.ts +258 -0
  137. package/dist/templates/research-workflow/agent.test.ts +525 -0
  138. package/dist/templates/research-workflow/agent.ts +94 -0
  139. package/dist/templates/research-workflow/shared.ts +35 -0
  140. package/dist/templates/research-workflow/tools/file_it_now.ts +22 -0
  141. package/dist/templates/research-workflow/tools/request_research.ts +33 -0
  142. package/dist/templates/research-workflow/tools/research_progress.ts +26 -0
  143. package/dist/templates/research-workflow/tools/research_status.ts +40 -0
  144. package/dist/templates/research-workflow/workflows/prompts.ts +143 -0
  145. package/dist/templates/research-workflow/workflows/research.ts +558 -0
  146. package/dist/templates/retail/agent.test.ts +319 -256
  147. package/dist/templates/retail/agent.ts +6 -46
  148. package/dist/templates/retail/authenticate.ts +2 -2
  149. package/dist/templates/retail/client.tsx +45 -24
  150. package/dist/templates/retail/registry.test.ts +40 -25
  151. package/dist/templates/retail/resolve.test.ts +17 -16
  152. package/dist/templates/retail/resolve.ts +32 -67
  153. package/dist/templates/retail/shared.test.ts +21 -19
  154. package/dist/templates/retail/shared.ts +61 -23
  155. package/dist/templates/retail/store.test.ts +47 -52
  156. package/dist/templates/retail/store.ts +92 -79
  157. package/dist/templates/retail/swap.test.ts +20 -17
  158. package/dist/templates/retail/swap.ts +7 -14
  159. package/dist/templates/retail/tools/cancel_pending_order.ts +7 -11
  160. package/dist/templates/retail/tools/exchange_delivered_order_items.ts +26 -14
  161. package/dist/templates/retail/tools/find_user_id_by_email.ts +5 -9
  162. package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +5 -7
  163. package/dist/templates/retail/tools/get_item_details.ts +7 -8
  164. package/dist/templates/retail/tools/get_order_details.ts +7 -8
  165. package/dist/templates/retail/tools/get_product_details.ts +6 -8
  166. package/dist/templates/retail/tools/get_user_details.ts +6 -8
  167. package/dist/templates/retail/tools/list_all_product_types.ts +5 -7
  168. package/dist/templates/retail/tools/modify_pending_order_address.ts +6 -10
  169. package/dist/templates/retail/tools/modify_pending_order_items.ts +8 -20
  170. package/dist/templates/retail/tools/modify_pending_order_payment.ts +7 -13
  171. package/dist/templates/retail/tools/modify_user_address.ts +6 -10
  172. package/dist/templates/retail/tools/return_delivered_order_items.ts +7 -13
  173. package/dist/templates/retail/tools/transfer_to_human_agents.ts +1 -1
  174. package/dist/templates/solo-rpg/agent.test.ts +169 -54
  175. package/dist/templates/solo-rpg/agent.ts +4 -22
  176. package/dist/templates/solo-rpg/client.tsx +19 -6
  177. package/dist/templates/solo-rpg/shared.ts +20 -20
  178. package/dist/templates/solo-rpg/tools/action_roll.ts +3 -5
  179. package/dist/templates/solo-rpg/tools/burn_momentum.ts +3 -5
  180. package/dist/templates/solo-rpg/tools/check_state.ts +7 -7
  181. package/dist/templates/solo-rpg/tools/load_game.ts +3 -3
  182. package/dist/templates/solo-rpg/tools/oracle.ts +19 -12
  183. package/dist/templates/solo-rpg/tools/save_game.ts +11 -8
  184. package/dist/templates/solo-rpg/tools/setup_character.ts +3 -3
  185. package/dist/templates/solo-rpg/tools/update_state.ts +13 -13
  186. package/dist/templates/support-line/agent.test.ts +343 -0
  187. package/dist/templates/support-line/agent.ts +27 -0
  188. package/dist/templates/support-line/client.tsx +122 -0
  189. package/dist/templates/support-line/graph.ts +224 -0
  190. package/dist/templates/support-line/knowledge.json +65 -0
  191. package/dist/templates/support-line/prompts.ts +95 -0
  192. package/dist/templates/support-line/shared.ts +240 -0
  193. package/dist/templates/support-line/system-prompt.md +17 -0
  194. package/dist/templates/support-line/tools/answer_question.ts +72 -0
  195. package/dist/templates/support-line/tools/list_topics.ts +22 -0
  196. package/dist/templates/support-line/tools/log_ticket.ts +30 -0
  197. package/dist/templates/transcription-workflow/agent.test.ts +563 -0
  198. package/dist/templates/transcription-workflow/agent.ts +92 -0
  199. package/dist/templates/transcription-workflow/client.tsx +234 -0
  200. package/dist/templates/transcription-workflow/workflows/transcribe.ts +416 -0
  201. package/dist/templates/transcription-workflow/workflows/wav.ts +314 -0
  202. package/dist/templates/travel-concierge/agent.test.ts +338 -0
  203. package/dist/templates/travel-concierge/agent.ts +29 -0
  204. package/dist/templates/travel-concierge/client.tsx +161 -0
  205. package/dist/templates/travel-concierge/routing.ts +138 -0
  206. package/dist/templates/travel-concierge/shared.ts +547 -0
  207. package/dist/templates/travel-concierge/system-prompt.md +24 -0
  208. package/dist/templates/travel-concierge/tools/book_car_rental.ts +20 -0
  209. package/dist/templates/travel-concierge/tools/book_excursion.ts +18 -0
  210. package/dist/templates/travel-concierge/tools/book_hotel.ts +20 -0
  211. package/dist/templates/travel-concierge/tools/cancel_action.ts +7 -0
  212. package/dist/templates/travel-concierge/tools/cancel_ticket.ts +16 -0
  213. package/dist/templates/travel-concierge/tools/complete_or_escalate.ts +7 -0
  214. package/dist/templates/travel-concierge/tools/confirm_action.ts +7 -0
  215. package/dist/templates/travel-concierge/tools/lookup_booking.ts +35 -0
  216. package/dist/templates/travel-concierge/tools/search_car_rentals.ts +33 -0
  217. package/dist/templates/travel-concierge/tools/search_excursions.ts +37 -0
  218. package/dist/templates/travel-concierge/tools/search_flights.ts +43 -0
  219. package/dist/templates/travel-concierge/tools/search_hotels.ts +36 -0
  220. package/dist/templates/travel-concierge/tools/to_car_rental_assistant.ts +11 -0
  221. package/dist/templates/travel-concierge/tools/to_excursion_assistant.ts +11 -0
  222. package/dist/templates/travel-concierge/tools/to_flight_assistant.ts +11 -0
  223. package/dist/templates/travel-concierge/tools/to_hotel_assistant.ts +11 -0
  224. package/dist/templates/travel-concierge/tools/update_ticket.ts +22 -0
  225. package/dist/templates/web-researcher/agent.ts +0 -2
  226. package/dist/templates/web-researcher/system-prompt.md +10 -0
  227. package/dist/{test-2LWBcXvY.mjs → test-B6ZBxSpk.mjs} +2 -2
  228. package/dist/typecheck.mjs +17 -15
  229. package/dist/worker-bundler-CIdDhZ0c.mjs +398 -0
  230. package/dist/worker-bundler.d.ts +14 -0
  231. package/dist/worker-bundler.mjs +1 -108
  232. package/dist/workflow-B-O97AqI.mjs +125 -0
  233. package/dist/workflow-bundler.d.ts +133 -0
  234. package/dist/workflow.d.ts +67 -0
  235. package/package.json +13 -9
  236. package/dist/build-DQJ1ZSm9.mjs +0 -39
@@ -1,16 +1,20 @@
1
- import { tool } from "@alexkroman1/aai";
1
+ import { isToolFailure } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
- import { findIncident, getApplicableProtocols, getState, incidentAgeMinutes } from "../shared.ts";
3
+ import {
4
+ dispatchSlot,
5
+ findIncident,
6
+ getApplicableProtocols,
7
+ incidentAgeMinutes,
8
+ } from "../shared.ts";
4
9
 
5
- export const incidentGet = tool({
10
+ export default dispatchSlot.tool({
6
11
  description: "Get full details on a specific incident including timeline and assigned resources.",
7
12
  inputSchema: z.object({
8
13
  incidentId: z.string().max(20).describe("The incident ID"),
9
14
  }),
10
- async execute(args, ctx) {
11
- const state = getState(ctx);
15
+ execute(args, state) {
12
16
  const inc = findIncident(state, args.incidentId);
13
- if ("error" in inc) return inc;
17
+ if (isToolFailure(inc)) return inc;
14
18
 
15
19
  const assignedResourceDetails = inc.assignedResources
16
20
  .map((rId) => {
@@ -1,18 +1,18 @@
1
- import { tool } from "@alexkroman1/aai";
1
+ import { isToolFailure } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import {
4
4
  assertNotResolved,
5
5
  calculateTriageScore,
6
+ dispatchSlot,
6
7
  findIncident,
7
8
  getApplicableProtocols,
8
9
  INCIDENT_TYPES,
9
10
  logEvent,
10
11
  recommendResources,
11
12
  SEVERITIES,
12
- updateState,
13
13
  } from "../shared.ts";
14
14
 
15
- export const incidentTriage = tool({
15
+ export default dispatchSlot.updateTool({
16
16
  description:
17
17
  "Triage an incident — confirm or override severity, type, hazards, and casualty count.",
18
18
  inputSchema: z.object({
@@ -27,52 +27,50 @@ export const incidentTriage = tool({
27
27
  casualtyUpdate: z.number().int().nonnegative().describe("Updated casualty count").optional(),
28
28
  notes: z.string().max(1000).describe("Triage notes").optional(),
29
29
  }),
30
- async execute(args, ctx) {
31
- return updateState(ctx, (state) => {
32
- const inc = findIncident(state, args.incidentId);
33
- if ("error" in inc) return inc;
34
- const blocked = assertNotResolved(inc, "triage");
35
- if (blocked) return blocked;
30
+ execute(args, state) {
31
+ const inc = findIncident(state, args.incidentId);
32
+ if (isToolFailure(inc)) return inc;
33
+ const blocked = assertNotResolved(inc, "triage");
34
+ if (blocked) return blocked;
36
35
 
37
- if (args.severity) inc.severity = args.severity;
38
- if (args.type) inc.type = args.type;
39
- for (const hazard of args.additionalHazards ?? []) {
40
- if (!inc.hazards.includes(hazard)) inc.hazards.push(hazard);
41
- }
42
- if (args.casualtyUpdate !== undefined) {
43
- inc.casualties.estimated = args.casualtyUpdate;
44
- }
45
- if (args.notes) logEvent(inc, `Triage note: ${args.notes}`);
36
+ if (args.severity) inc.severity = args.severity;
37
+ if (args.type) inc.type = args.type;
38
+ for (const hazard of args.additionalHazards ?? []) {
39
+ if (!inc.hazards.includes(hazard)) inc.hazards.push(hazard);
40
+ }
41
+ if (args.casualtyUpdate !== undefined) {
42
+ inc.casualties.estimated = args.casualtyUpdate;
43
+ }
44
+ if (args.notes) logEvent(inc, `Triage note: ${args.notes}`);
46
45
 
47
- inc.triageScore = calculateTriageScore(
48
- inc.severity,
49
- inc.type,
50
- inc.casualties.estimated,
51
- inc.hazards.length,
52
- );
53
- inc.status = "triaged";
54
- logEvent(inc, `Triaged: ${inc.severity} ${inc.type}, score ${inc.triageScore}`);
46
+ inc.triageScore = calculateTriageScore(
47
+ inc.severity,
48
+ inc.type,
49
+ inc.casualties.estimated,
50
+ inc.hazards.length,
51
+ );
52
+ inc.status = "triaged";
53
+ logEvent(inc, `Triaged: ${inc.severity} ${inc.type}, score ${inc.triageScore}`);
55
54
 
56
- const protocols = getApplicableProtocols(inc.type, inc.severity);
57
- const recommended = recommendResources(inc.type, inc.severity, state);
55
+ const protocols = getApplicableProtocols(inc.type, inc.severity);
56
+ const recommended = recommendResources(inc.type, inc.severity, state);
58
57
 
59
- return {
60
- incidentId: args.incidentId,
61
- severity: inc.severity,
62
- type: inc.type,
63
- triageScore: inc.triageScore,
64
- hazards: inc.hazards,
65
- estimatedCasualties: inc.casualties.estimated,
66
- protocols: protocols.map((p) => ({
67
- name: p.name,
68
- steps: p.steps,
69
- requiredResources: p.requiredResources,
70
- })),
71
- recommendedResources: recommended.map((r) => ({
72
- callsign: r.callsign,
73
- type: r.type,
74
- })),
75
- };
76
- });
58
+ return {
59
+ incidentId: args.incidentId,
60
+ severity: inc.severity,
61
+ type: inc.type,
62
+ triageScore: inc.triageScore,
63
+ hazards: inc.hazards,
64
+ estimatedCasualties: inc.casualties.estimated,
65
+ protocols: protocols.map((p) => ({
66
+ name: p.name,
67
+ steps: p.steps,
68
+ requiredResources: p.requiredResources,
69
+ })),
70
+ recommendedResources: recommended.map((r) => ({
71
+ callsign: r.callsign,
72
+ type: r.type,
73
+ })),
74
+ };
77
75
  },
78
76
  });
@@ -1,8 +1,8 @@
1
- import { tool } from "@alexkroman1/aai";
1
+ import { isToolFailure } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
- import { assertNotResolved, findIncident, logEvent, updateState } from "../shared.ts";
3
+ import { assertNotResolved, dispatchSlot, findIncident, logEvent } from "../shared.ts";
4
4
 
5
- export const incidentUpdateStatus = tool({
5
+ export default dispatchSlot.updateTool({
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"),
@@ -16,53 +16,51 @@ export const incidentUpdateStatus = tool({
16
16
  .describe("Updated casualty numbers")
17
17
  .optional(),
18
18
  }),
19
- async execute(args, ctx) {
20
- return updateState(ctx, (state) => {
21
- const inc = findIncident(state, args.incidentId);
22
- if ("error" in inc) return inc;
23
- const blocked = assertNotResolved(inc, `set status to ${args.status}`);
24
- if (blocked) return blocked;
19
+ execute(args, state) {
20
+ const inc = findIncident(state, args.incidentId);
21
+ if (isToolFailure(inc)) return inc;
22
+ const blocked = assertNotResolved(inc, `set status to ${args.status}`);
23
+ if (blocked) return blocked;
25
24
 
26
- inc.status = args.status;
27
- logEvent(inc, `Status → ${args.status}${args.notes ? `: ${args.notes}` : ""}`);
25
+ inc.status = args.status;
26
+ logEvent(inc, `Status → ${args.status}${args.notes ? `: ${args.notes}` : ""}`);
28
27
 
29
- if (args.casualtyUpdate) {
30
- if (args.casualtyUpdate.confirmed !== undefined) {
31
- inc.casualties.confirmed = args.casualtyUpdate.confirmed;
32
- }
33
- if (args.casualtyUpdate.treated !== undefined) {
34
- inc.casualties.treated = args.casualtyUpdate.treated;
35
- }
28
+ if (args.casualtyUpdate) {
29
+ if (args.casualtyUpdate.confirmed !== undefined) {
30
+ inc.casualties.confirmed = args.casualtyUpdate.confirmed;
36
31
  }
32
+ if (args.casualtyUpdate.treated !== undefined) {
33
+ inc.casualties.treated = args.casualtyUpdate.treated;
34
+ }
35
+ }
37
36
 
38
- // Only touch resources still assigned to THIS incident — a unit that
39
- // radioed available and was re-dispatched elsewhere belongs to its
40
- // new incident now.
41
- const ownResources = state.resources.filter((r) => r.assignedIncident === inc.id);
37
+ // Only touch resources still assigned to THIS incident — a unit that
38
+ // radioed available and was re-dispatched elsewhere belongs to its
39
+ // new incident now.
40
+ const ownResources = state.resources.filter((r) => r.assignedIncident === inc.id);
42
41
 
43
- if (args.status === "resolved") {
44
- for (const r of ownResources) {
45
- r.status = "returning";
46
- r.assignedIncident = null;
47
- r.eta = null;
48
- }
49
- inc.assignedResources = [];
50
- logEvent(inc, "All resources released — incident closed");
42
+ if (args.status === "resolved") {
43
+ for (const r of ownResources) {
44
+ r.status = "returning";
45
+ r.assignedIncident = null;
46
+ r.eta = null;
51
47
  }
48
+ inc.assignedResources = [];
49
+ logEvent(inc, "All resources released — incident closed");
50
+ }
52
51
 
53
- if (args.status === "en_route" || args.status === "on_scene") {
54
- for (const r of ownResources) {
55
- r.status = args.status;
56
- if (args.status === "on_scene") r.eta = null;
57
- }
52
+ if (args.status === "en_route" || args.status === "on_scene") {
53
+ for (const r of ownResources) {
54
+ r.status = args.status;
55
+ if (args.status === "on_scene") r.eta = null;
58
56
  }
57
+ }
59
58
 
60
- return {
61
- incidentId: args.incidentId,
62
- newStatus: args.status,
63
- timeline: inc.timeline.slice(-5).map((t) => t.event),
64
- casualties: inc.casualties,
65
- };
66
- });
59
+ return {
60
+ incidentId: args.incidentId,
61
+ newStatus: args.status,
62
+ timeline: inc.timeline.slice(-5).map((t) => t.event),
63
+ casualties: inc.casualties,
64
+ };
67
65
  },
68
66
  });
@@ -1,12 +1,9 @@
1
- import { tool } from "@alexkroman1/aai";
2
- import { getState, incidentAgeMinutes, resourceBrief, resourceUtilization } from "../shared.ts";
1
+ import { dispatchSlot, incidentAgeMinutes, resourceBrief, resourceUtilization } from "../shared.ts";
3
2
 
4
- export const opsDashboard = tool({
3
+ export default dispatchSlot.tool({
5
4
  description:
6
5
  "Get the full operational dashboard: alert level, resource utilization, active incidents, and available resources.",
7
- async execute(_args, ctx) {
8
- const state = getState(ctx);
9
-
6
+ execute(_args, state) {
10
7
  const activeIncidents = Object.values(state.incidents)
11
8
  .filter((i) => i.status !== "resolved")
12
9
  .sort((a, b) => b.triageScore - a.triageScore);
@@ -2,7 +2,7 @@ import { tool } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import { getApplicableProtocols, INCIDENT_TYPES, SEVERITIES } from "../shared.ts";
4
4
 
5
- export const opsProtocols = tool({
5
+ export default 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"),
@@ -1,7 +1,6 @@
1
- import { tool } from "@alexkroman1/aai";
2
1
  import { z } from "zod";
3
2
  import type { Incident, IncidentType, Severity } from "../shared.ts";
4
- import { calculateTriageScore, createIncident, updateState } from "../shared.ts";
3
+ import { calculateTriageScore, createIncident, dispatchSlot } from "../shared.ts";
5
4
 
6
5
  type ScenarioIncident = Pick<Incident, "location" | "description" | "type" | "severity">;
7
6
  type ScenarioDef = { narrative: string; incidents: ScenarioIncident[] };
@@ -117,33 +116,31 @@ const scenarios = {
117
116
  type ScenarioName = keyof typeof scenarios;
118
117
  const SCENARIO_NAMES = Object.keys(scenarios) as [ScenarioName, ...ScenarioName[]];
119
118
 
120
- export const opsRunScenario = tool({
119
+ export default dispatchSlot.updateTool({
121
120
  description: "Run a training scenario that creates simulated incidents for dispatch practice.",
122
121
  inputSchema: z.object({
123
122
  scenario: z.enum(SCENARIO_NAMES).describe("Scenario type to simulate"),
124
123
  }),
125
- async execute(args, ctx) {
126
- return updateState(ctx, (state) => {
127
- const s = scenarios[args.scenario];
124
+ execute(args, state) {
125
+ const s = scenarios[args.scenario];
128
126
 
129
- const created: string[] = [];
130
- for (const scenarioInc of s.incidents) {
131
- const fullInc = createIncident(state, {
132
- ...scenarioInc,
133
- callerName: "Scenario",
134
- callerPhone: "N/A",
135
- triageScore: calculateTriageScore(scenarioInc.severity, scenarioInc.type, 0, 0),
136
- timeline: [{ time: Date.now(), event: `SCENARIO: ${scenarioInc.description}` }],
137
- });
138
- created.push(fullInc.id);
139
- }
127
+ const created: string[] = [];
128
+ for (const scenarioInc of s.incidents) {
129
+ const fullInc = createIncident(state, {
130
+ ...scenarioInc,
131
+ callerName: "Scenario",
132
+ callerPhone: "N/A",
133
+ triageScore: calculateTriageScore(scenarioInc.severity, scenarioInc.type, 0, 0),
134
+ timeline: [{ time: Date.now(), event: `SCENARIO: ${scenarioInc.description}` }],
135
+ });
136
+ created.push(fullInc.id);
137
+ }
140
138
 
141
- return {
142
- scenario: args.scenario,
143
- narrative: s.narrative,
144
- incidentsCreated: created,
145
- message: `SCENARIO ACTIVE: ${s.narrative}. ${created.length} incidents created. Awaiting dispatch orders.`,
146
- };
147
- });
139
+ return {
140
+ scenario: args.scenario,
141
+ narrative: s.narrative,
142
+ incidentsCreated: created,
143
+ message: `SCENARIO ACTIVE: ${s.narrative}. ${created.length} incidents created. Awaiting dispatch orders.`,
144
+ };
148
145
  },
149
146
  });
@@ -1,15 +1,15 @@
1
- import { tool } from "@alexkroman1/aai";
1
+ import { isToolFailure } from "@alexkroman1/aai";
2
2
  import { z } from "zod";
3
3
  import type { Resource } from "../shared.ts";
4
4
  import {
5
5
  assertNotResolved,
6
+ dispatchSlot,
6
7
  findIncident,
7
8
  logEvent,
8
9
  recommendResources,
9
- updateState,
10
10
  } from "../shared.ts";
11
11
 
12
- export const resourcesDispatch = tool({
12
+ export default dispatchSlot.updateTool({
13
13
  description:
14
14
  "Dispatch units to an incident. Can auto-dispatch recommended resources or manually specify callsigns.",
15
15
  inputSchema: z.object({
@@ -30,68 +30,66 @@ export const resourcesDispatch = tool({
30
30
  .describe("Dispatch priority — affects simulated ETA")
31
31
  .optional(),
32
32
  }),
33
- async execute(args, ctx) {
34
- return updateState(ctx, (state) => {
35
- const inc = findIncident(state, args.incidentId);
36
- if ("error" in inc) return inc;
37
- const blocked = assertNotResolved(inc, "dispatch resources");
38
- if (blocked) return blocked;
33
+ execute(args, state) {
34
+ const inc = findIncident(state, args.incidentId);
35
+ if (isToolFailure(inc)) return inc;
36
+ const blocked = assertNotResolved(inc, "dispatch resources");
37
+ if (blocked) return blocked;
39
38
 
40
- const dispatched: { callsign: string; type: string; eta: number }[] = [];
41
- const failed: { callsign: string; reason: string }[] = [];
39
+ const dispatched: { callsign: string; type: string; eta: number }[] = [];
40
+ const failed: { callsign: string; reason: string }[] = [];
42
41
 
43
- // The literal "auto" callsign means the same thing as autoDispatch.
44
- const wantsAuto =
45
- args.autoDispatch || args.callsigns?.some((cs) => cs.toLowerCase() === "auto");
42
+ // The literal "auto" callsign means the same thing as autoDispatch.
43
+ const wantsAuto =
44
+ args.autoDispatch || args.callsigns?.some((cs) => cs.toLowerCase() === "auto");
46
45
 
47
- let resourcesToDispatch: Resource[] = [];
46
+ let resourcesToDispatch: Resource[] = [];
48
47
 
49
- if (wantsAuto) {
50
- resourcesToDispatch = recommendResources(inc.type, inc.severity, state);
51
- } else if (args.callsigns) {
52
- for (const cs of args.callsigns) {
53
- const r = state.resources.find((r) => r.callsign.toLowerCase() === cs.toLowerCase());
54
- if (!r) {
55
- failed.push({ callsign: cs, reason: "Not found" });
56
- continue;
57
- }
58
- if (r.status !== "available") {
59
- failed.push({ callsign: cs, reason: `Currently ${r.status}` });
60
- continue;
61
- }
62
- resourcesToDispatch.push(r);
48
+ if (wantsAuto) {
49
+ resourcesToDispatch = recommendResources(inc.type, inc.severity, state);
50
+ } else if (args.callsigns) {
51
+ for (const cs of args.callsigns) {
52
+ const r = state.resources.find((r) => r.callsign.toLowerCase() === cs.toLowerCase());
53
+ if (!r) {
54
+ failed.push({ callsign: cs, reason: "Not found" });
55
+ continue;
63
56
  }
57
+ if (r.status !== "available") {
58
+ failed.push({ callsign: cs, reason: `Currently ${r.status}` });
59
+ continue;
60
+ }
61
+ resourcesToDispatch.push(r);
64
62
  }
63
+ }
65
64
 
66
- const etaBase = args.priority === "emergency" ? 3 : args.priority === "priority" ? 6 : 10;
65
+ const etaBase = args.priority === "emergency" ? 3 : args.priority === "priority" ? 6 : 10;
67
66
 
68
- for (const r of resourcesToDispatch) {
69
- const eta = etaBase + Math.floor(Math.random() * 5);
70
- r.status = "dispatched";
71
- r.assignedIncident = args.incidentId;
72
- r.eta = eta;
73
- inc.assignedResources.push(r.id);
74
- dispatched.push({ callsign: r.callsign, type: r.type, eta });
75
- logEvent(inc, `Dispatched ${r.callsign} — ETA ${eta} min`);
76
- }
67
+ for (const r of resourcesToDispatch) {
68
+ const eta = etaBase + Math.floor(Math.random() * 5);
69
+ r.status = "dispatched";
70
+ r.assignedIncident = args.incidentId;
71
+ r.eta = eta;
72
+ inc.assignedResources.push(r.id);
73
+ dispatched.push({ callsign: r.callsign, type: r.type, eta });
74
+ logEvent(inc, `Dispatched ${r.callsign} — ETA ${eta} min`);
75
+ }
77
76
 
78
- if (dispatched.length > 0) {
79
- inc.status = "dispatched";
80
- }
77
+ if (dispatched.length > 0) {
78
+ inc.status = "dispatched";
79
+ }
81
80
 
82
- const availableCount = state.resources.filter((r) => r.status === "available").length;
81
+ const availableCount = state.resources.filter((r) => r.status === "available").length;
83
82
 
84
- return {
85
- incidentId: args.incidentId,
86
- dispatched,
87
- failed: failed.length > 0 ? failed : undefined,
88
- totalAssignedToIncident: inc.assignedResources.length,
89
- remainingAvailableResources: availableCount,
90
- capacityWarning:
91
- availableCount <= 3
92
- ? "WARNING: Resource capacity critically low. Consider mutual aid."
93
- : undefined,
94
- };
95
- });
83
+ return {
84
+ incidentId: args.incidentId,
85
+ dispatched,
86
+ failed: failed.length > 0 ? failed : undefined,
87
+ totalAssignedToIncident: inc.assignedResources.length,
88
+ remainingAvailableResources: availableCount,
89
+ capacityWarning:
90
+ availableCount <= 3
91
+ ? "WARNING: Resource capacity critically low. Consider mutual aid."
92
+ : undefined,
93
+ };
96
94
  },
97
95
  });
@@ -1,8 +1,7 @@
1
- import { tool } from "@alexkroman1/aai";
2
1
  import { z } from "zod";
3
- import { getState, RESOURCE_TYPES } from "../shared.ts";
2
+ import { dispatchSlot, RESOURCE_TYPES } from "../shared.ts";
4
3
 
5
- export const resourcesGetAvailable = tool({
4
+ export default dispatchSlot.tool({
6
5
  description: "List available resources, optionally filtered by type.",
7
6
  inputSchema: z.object({
8
7
  type: z
@@ -10,8 +9,7 @@ export const resourcesGetAvailable = tool({
10
9
  .describe("Filter by resource type, or 'all'")
11
10
  .optional(),
12
11
  }),
13
- async execute(args, ctx) {
14
- const state = getState(ctx);
12
+ execute(args, state) {
15
13
  let resources = state.resources;
16
14
  if (args.type && args.type !== "all") {
17
15
  resources = resources.filter((r) => r.type === args.type);
@@ -1,62 +1,59 @@
1
- import { tool } from "@alexkroman1/aai";
2
1
  import { z } from "zod";
3
- import { logEvent, RESOURCE_STATUSES, updateState } from "../shared.ts";
2
+ import { dispatchSlot, logEvent, RESOURCE_STATUSES } from "../shared.ts";
4
3
 
5
- export const resourcesUpdateStatus = tool({
4
+ export default dispatchSlot.updateTool({
6
5
  description: "Update a resource unit's status when it radios in.",
7
6
  inputSchema: z.object({
8
7
  callsign: z.string().max(50).describe("The resource callsign"),
9
8
  status: z.enum(RESOURCE_STATUSES).describe("New status"),
10
9
  notes: z.string().max(1000).describe("Status notes").optional(),
11
10
  }),
12
- async execute(args, ctx) {
13
- return updateState(ctx, (state) => {
14
- const resource = state.resources.find(
15
- (r) => r.callsign.toLowerCase() === args.callsign.toLowerCase(),
16
- );
17
- if (!resource) {
18
- return { error: `Resource ${args.callsign} not found` };
11
+ execute(args, state) {
12
+ const resource = state.resources.find(
13
+ (r) => r.callsign.toLowerCase() === args.callsign.toLowerCase(),
14
+ );
15
+ if (!resource) {
16
+ return { error: `Resource ${args.callsign} not found` };
17
+ }
18
+
19
+ const previousStatus = resource.status;
20
+
21
+ // Log to the incident timeline BEFORE unassigning, so the
22
+ // return-to-available transition is recorded too.
23
+ if (resource.assignedIncident) {
24
+ const inc = state.incidents[resource.assignedIncident];
25
+ if (inc) {
26
+ logEvent(
27
+ inc,
28
+ `${resource.callsign}: ${previousStatus} → ${args.status}${args.notes ? ` (${args.notes})` : ""}`,
29
+ );
19
30
  }
31
+ }
20
32
 
21
- const previousStatus = resource.status;
33
+ resource.status = args.status;
22
34
 
23
- // Log to the incident timeline BEFORE unassigning, so the
24
- // return-to-available transition is recorded too.
35
+ if (args.status === "available") {
36
+ // Detach from the old incident on BOTH sides — leaving the id in
37
+ // assignedResources lets that incident later yank a unit that has
38
+ // been re-dispatched elsewhere.
25
39
  if (resource.assignedIncident) {
26
40
  const inc = state.incidents[resource.assignedIncident];
27
41
  if (inc) {
28
- logEvent(
29
- inc,
30
- `${resource.callsign}: ${previousStatus} → ${args.status}${args.notes ? ` (${args.notes})` : ""}`,
31
- );
42
+ inc.assignedResources = inc.assignedResources.filter((id) => id !== resource.id);
32
43
  }
33
44
  }
45
+ resource.assignedIncident = null;
46
+ resource.eta = null;
47
+ }
48
+ if (args.status === "on_scene") {
49
+ resource.eta = null;
50
+ }
34
51
 
35
- resource.status = args.status;
36
-
37
- if (args.status === "available") {
38
- // Detach from the old incident on BOTH sides — leaving the id in
39
- // assignedResources lets that incident later yank a unit that has
40
- // been re-dispatched elsewhere.
41
- if (resource.assignedIncident) {
42
- const inc = state.incidents[resource.assignedIncident];
43
- if (inc) {
44
- inc.assignedResources = inc.assignedResources.filter((id) => id !== resource.id);
45
- }
46
- }
47
- resource.assignedIncident = null;
48
- resource.eta = null;
49
- }
50
- if (args.status === "on_scene") {
51
- resource.eta = null;
52
- }
53
-
54
- return {
55
- callsign: resource.callsign,
56
- previousStatus,
57
- newStatus: args.status,
58
- assignedIncident: resource.assignedIncident,
59
- };
60
- });
52
+ return {
53
+ callsign: resource.callsign,
54
+ previousStatus,
55
+ newStatus: args.status,
56
+ assignedIncident: resource.assignedIncident,
57
+ };
61
58
  },
62
59
  });