@alexkroman1/aai-cli 5.14.0 → 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.
- package/dist/{_agent-C8Jk-ZcP.mjs → _agent-vGW5SBnX.mjs} +23 -5
- package/dist/_agent.d.ts +18 -0
- package/dist/{_api-client-BX8Qv51n.mjs → _api-client-LgLksMhN.mjs} +45 -8
- package/dist/_api-client.d.ts +39 -0
- package/dist/{_bundler-BuIyDdvs.mjs → _bundler-BapCUUJN.mjs} +42 -14
- package/dist/_bundler.d.ts +43 -5
- package/dist/_cli-common.d.ts +67 -3
- package/dist/{_config-CzwAWOWr.mjs → _config-D_s09e7g.mjs} +36 -18
- package/dist/_deploy.d.ts +2 -5
- package/dist/_dev-restart.d.ts +6 -1
- package/dist/{_dev-server-Ch7K8e8i.mjs → _dev-server-DQ1t9sbw.mjs} +94 -38
- package/dist/_dev-server.d.ts +30 -2
- package/dist/_e2e-test-utils.d.ts +80 -0
- package/dist/_fault-mode.d.ts +175 -0
- package/dist/{_init-CbkrE2wq.mjs → _init-CpISqoR8.mjs} +3 -3
- package/dist/{_output-CC300DzW.mjs → _output-CKkmWs7i.mjs} +8 -1
- package/dist/_output.d.ts +9 -2
- package/dist/{_server-common-61fL__39.mjs → _server-common-6e0QI4mq.mjs} +1 -1
- package/dist/{_slug-api-D30zPmsn.mjs → _slug-api-D2heILuC.mjs} +2 -2
- package/dist/{_studio-D2ciIhbi.mjs → _studio-zAJycZ8j.mjs} +3 -3
- package/dist/{_templates-B1kt3BGt.mjs → _templates-iDGjGiPf.mjs} +4 -6
- package/dist/{_typecheck-gate-4v9UBZHh.mjs → _typecheck-gate-BXvUNnfs.mjs} +1 -1
- package/dist/{_utils-0DHbcqUb.mjs → _utils-B8QmtFhK.mjs} +21 -7
- package/dist/_utils.d.ts +18 -2
- package/dist/{_vite-env-Dg_QlVv0.mjs → _vite-env-BNveawd1.mjs} +31 -1
- package/dist/_vite-env.d.ts +30 -0
- package/dist/build-BO1Ni6oJ.mjs +62 -0
- package/dist/build.d.ts +19 -0
- package/dist/cli-workflow.d.ts +10 -0
- package/dist/cli.d.ts +1 -2
- package/dist/cli.mjs +406 -224
- package/dist/{client-bundler-C9qXL8A2.mjs → client-bundler-B8Q9F8gJ.mjs} +3 -22
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-DCRX3d96.mjs → delete-4I0uNR4a.mjs} +6 -7
- package/dist/delete.d.ts +2 -8
- package/dist/{deploy-DjsEV-40.mjs → deploy-DJ3HRcia.mjs} +13 -14
- package/dist/{dev-CvPH5dbF.mjs → dev-C6SWaAZP.mjs} +3 -3
- package/dist/{eject-LgBRfnbH.mjs → eject-Zrzk5KV3.mjs} +41 -15
- package/dist/eject.d.ts +30 -3
- package/dist/{init-BppxMR8r.mjs → init-BTRGiPQr.mjs} +61 -26
- package/dist/init.d.ts +11 -0
- package/dist/{login-BQQaxJhL.mjs → login-k0Z3VQu9.mjs} +5 -5
- package/dist/project-config.mjs +1 -1
- package/dist/scaffold/CLAUDE.md +498 -91
- package/dist/scaffold/package.json +11 -8
- package/dist/scaffold/pnpm-workspace.yaml +8 -0
- package/dist/scaffold/server.mjs +53 -57
- package/dist/{secret-Ds9dvqAj.mjs → secret-DzSQx1Ds.mjs} +6 -3
- package/dist/{storage-DbrQSHFk.mjs → storage-C-Do0mIA.mjs} +18 -6
- package/dist/{studio-GSFd4s5O.mjs → studio-BGVmCA2G.mjs} +10 -10
- package/dist/templates/code-interpreter/agent.ts +0 -2
- package/dist/templates/dispatch-center/agent.test.ts +17 -19
- package/dist/templates/dispatch-center/agent.ts +2 -29
- package/dist/templates/dispatch-center/client.tsx +33 -16
- package/dist/templates/dispatch-center/shared.ts +53 -19
- package/dist/templates/dispatch-center/tools/incident_add_note.ts +12 -14
- package/dist/templates/dispatch-center/tools/incident_create.ts +41 -44
- package/dist/templates/dispatch-center/tools/incident_escalate.ts +59 -61
- package/dist/templates/dispatch-center/tools/incident_get.ts +3 -4
- package/dist/templates/dispatch-center/tools/incident_triage.ts +43 -45
- package/dist/templates/dispatch-center/tools/incident_update_status.ts +39 -41
- package/dist/templates/dispatch-center/tools/ops_dashboard.ts +2 -5
- package/dist/templates/dispatch-center/tools/ops_protocols.ts +1 -1
- package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +20 -23
- package/dist/templates/dispatch-center/tools/resources_dispatch.ts +52 -54
- package/dist/templates/dispatch-center/tools/resources_get_available.ts +2 -4
- package/dist/templates/dispatch-center/tools/resources_update_status.ts +39 -42
- package/dist/templates/embedded-assets/agent.test.ts +83 -0
- package/dist/templates/embedded-assets/agent.ts +1 -48
- package/dist/templates/embedded-assets/shared.ts +17 -0
- package/dist/templates/embedded-assets/system-prompt.md +13 -0
- package/dist/templates/embedded-assets/tools/list_topics.ts +9 -0
- package/dist/templates/embedded-assets/tools/search_knowledge.ts +26 -0
- package/dist/templates/health-assistant/agent.test.ts +169 -0
- package/dist/templates/health-assistant/agent.ts +1 -166
- package/dist/templates/health-assistant/fda.ts +100 -0
- package/dist/templates/health-assistant/tools/check_drug_interaction.ts +59 -0
- package/dist/templates/health-assistant/tools/medication_lookup.ts +31 -0
- package/dist/templates/infocom-adventure/agent.test.ts +205 -0
- package/dist/templates/infocom-adventure/agent.ts +3 -106
- package/dist/templates/infocom-adventure/client.tsx +28 -12
- package/dist/templates/infocom-adventure/shared.ts +28 -11
- package/dist/templates/infocom-adventure/tools/game_state_drop.ts +13 -0
- package/dist/templates/infocom-adventure/tools/game_state_flag.ts +13 -0
- package/dist/templates/infocom-adventure/tools/game_state_get.ts +16 -0
- package/dist/templates/infocom-adventure/tools/game_state_history.ts +14 -0
- package/dist/templates/infocom-adventure/tools/game_state_move.ts +14 -0
- package/dist/templates/infocom-adventure/tools/game_state_restart.ts +13 -0
- package/dist/templates/infocom-adventure/tools/game_state_score.ts +13 -0
- package/dist/templates/infocom-adventure/tools/game_state_take.ts +13 -0
- package/dist/templates/link-digest/agent.test.ts +223 -0
- package/dist/templates/link-digest/agent.ts +79 -0
- package/dist/templates/link-digest/client.tsx +146 -0
- package/dist/templates/link-digest/workflows/digest.ts +248 -0
- package/dist/templates/math-buddy/agent.ts +0 -2
- package/dist/templates/night-owl/agent.test.ts +80 -0
- package/dist/templates/night-owl/agent.ts +1 -68
- package/dist/templates/night-owl/system-prompt.md +10 -0
- package/dist/templates/night-owl/tools/recommend.ts +64 -0
- package/dist/templates/personal-finance/agent.ts +0 -2
- package/dist/templates/pizza-ordering/agent.test.ts +52 -47
- package/dist/templates/pizza-ordering/agent.ts +9 -158
- package/dist/templates/pizza-ordering/shared.ts +35 -12
- package/dist/templates/pizza-ordering/tools/add_pizza.ts +31 -0
- package/dist/templates/pizza-ordering/tools/place_order.ts +22 -0
- package/dist/templates/pizza-ordering/tools/remove_pizza.ts +22 -0
- package/dist/templates/pizza-ordering/tools/set_customer_name.ts +13 -0
- package/dist/templates/pizza-ordering/tools/update_pizza.ts +28 -0
- package/dist/templates/pizza-ordering/tools/view_order.ts +21 -0
- package/dist/templates/plan-and-execute/agent.test.ts +411 -0
- package/dist/templates/plan-and-execute/agent.ts +23 -0
- package/dist/templates/plan-and-execute/client.tsx +115 -0
- package/dist/templates/plan-and-execute/graph.ts +178 -0
- package/dist/templates/plan-and-execute/prompts.ts +110 -0
- package/dist/templates/plan-and-execute/shared.ts +161 -0
- package/dist/templates/plan-and-execute/system-prompt.md +18 -0
- package/dist/templates/plan-and-execute/tools/plan_status.ts +20 -0
- package/dist/templates/plan-and-execute/tools/revise_plan.ts +63 -0
- package/dist/templates/plan-and-execute/tools/start_plan.ts +51 -0
- package/dist/templates/plan-and-execute/tools/work_next_step.ts +101 -0
- package/dist/templates/recap-workflow/agent.test.ts +762 -0
- package/dist/templates/recap-workflow/agent.ts +95 -0
- package/dist/templates/recap-workflow/shared.ts +43 -0
- package/dist/templates/recap-workflow/tools/cancel_recap.ts +23 -0
- package/dist/templates/recap-workflow/tools/keep_transcript.ts +31 -0
- package/dist/templates/recap-workflow/tools/recap_progress.ts +27 -0
- package/dist/templates/recap-workflow/tools/recap_status.ts +46 -0
- package/dist/templates/recap-workflow/tools/request_recap.ts +43 -0
- package/dist/templates/recap-workflow/workflows/recap.ts +544 -0
- package/dist/templates/recap-workflow/workflows/tokens.ts +26 -0
- package/dist/templates/redline/agent.test.ts +222 -0
- package/dist/templates/redline/agent.ts +89 -0
- package/dist/templates/redline/client.tsx +184 -0
- package/dist/templates/redline/workflows/prompts.ts +68 -0
- package/dist/templates/redline/workflows/redline.ts +258 -0
- package/dist/templates/research-workflow/agent.test.ts +525 -0
- package/dist/templates/research-workflow/agent.ts +94 -0
- package/dist/templates/research-workflow/shared.ts +35 -0
- package/dist/templates/research-workflow/tools/file_it_now.ts +22 -0
- package/dist/templates/research-workflow/tools/request_research.ts +33 -0
- package/dist/templates/research-workflow/tools/research_progress.ts +26 -0
- package/dist/templates/research-workflow/tools/research_status.ts +40 -0
- package/dist/templates/research-workflow/workflows/prompts.ts +143 -0
- package/dist/templates/research-workflow/workflows/research.ts +558 -0
- package/dist/templates/retail/agent.test.ts +236 -172
- package/dist/templates/retail/agent.ts +5 -42
- package/dist/templates/retail/client.tsx +33 -11
- package/dist/templates/retail/registry.test.ts +31 -16
- package/dist/templates/retail/resolve.ts +28 -64
- package/dist/templates/retail/shared.test.ts +4 -3
- package/dist/templates/retail/shared.ts +24 -7
- package/dist/templates/retail/store.test.ts +12 -10
- package/dist/templates/retail/store.ts +69 -30
- package/dist/templates/retail/tools/cancel_pending_order.ts +4 -9
- package/dist/templates/retail/tools/exchange_delivered_order_items.ts +22 -11
- package/dist/templates/retail/tools/find_user_id_by_email.ts +5 -9
- package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +5 -7
- package/dist/templates/retail/tools/get_item_details.ts +5 -7
- package/dist/templates/retail/tools/get_order_details.ts +5 -7
- package/dist/templates/retail/tools/get_product_details.ts +4 -7
- package/dist/templates/retail/tools/get_user_details.ts +4 -7
- package/dist/templates/retail/tools/list_all_product_types.ts +5 -7
- package/dist/templates/retail/tools/modify_pending_order_address.ts +4 -9
- package/dist/templates/retail/tools/modify_pending_order_items.ts +4 -16
- package/dist/templates/retail/tools/modify_pending_order_payment.ts +3 -9
- package/dist/templates/retail/tools/modify_user_address.ts +4 -9
- package/dist/templates/retail/tools/return_delivered_order_items.ts +3 -9
- package/dist/templates/retail/tools/transfer_to_human_agents.ts +1 -1
- package/dist/templates/solo-rpg/agent.test.ts +152 -29
- package/dist/templates/solo-rpg/agent.ts +3 -21
- package/dist/templates/solo-rpg/client.tsx +19 -6
- package/dist/templates/solo-rpg/shared.ts +19 -11
- package/dist/templates/solo-rpg/tools/action_roll.ts +2 -4
- package/dist/templates/solo-rpg/tools/burn_momentum.ts +2 -4
- package/dist/templates/solo-rpg/tools/check_state.ts +6 -6
- package/dist/templates/solo-rpg/tools/load_game.ts +1 -1
- package/dist/templates/solo-rpg/tools/oracle.ts +18 -11
- package/dist/templates/solo-rpg/tools/save_game.ts +10 -7
- package/dist/templates/solo-rpg/tools/setup_character.ts +1 -1
- package/dist/templates/solo-rpg/tools/update_state.ts +3 -4
- package/dist/templates/support-line/agent.test.ts +343 -0
- package/dist/templates/support-line/agent.ts +27 -0
- package/dist/templates/support-line/client.tsx +122 -0
- package/dist/templates/support-line/graph.ts +224 -0
- package/dist/templates/support-line/knowledge.json +65 -0
- package/dist/templates/support-line/prompts.ts +95 -0
- package/dist/templates/support-line/shared.ts +240 -0
- package/dist/templates/support-line/system-prompt.md +17 -0
- package/dist/templates/support-line/tools/answer_question.ts +72 -0
- package/dist/templates/support-line/tools/list_topics.ts +22 -0
- package/dist/templates/support-line/tools/log_ticket.ts +30 -0
- package/dist/templates/transcription-workflow/agent.test.ts +563 -0
- package/dist/templates/transcription-workflow/agent.ts +92 -0
- package/dist/templates/transcription-workflow/client.tsx +234 -0
- package/dist/templates/transcription-workflow/workflows/transcribe.ts +416 -0
- package/dist/templates/transcription-workflow/workflows/wav.ts +314 -0
- package/dist/templates/travel-concierge/agent.test.ts +338 -0
- package/dist/templates/travel-concierge/agent.ts +29 -0
- package/dist/templates/travel-concierge/client.tsx +161 -0
- package/dist/templates/travel-concierge/routing.ts +138 -0
- package/dist/templates/travel-concierge/shared.ts +547 -0
- package/dist/templates/travel-concierge/system-prompt.md +24 -0
- package/dist/templates/travel-concierge/tools/book_car_rental.ts +20 -0
- package/dist/templates/travel-concierge/tools/book_excursion.ts +18 -0
- package/dist/templates/travel-concierge/tools/book_hotel.ts +20 -0
- package/dist/templates/travel-concierge/tools/cancel_action.ts +7 -0
- package/dist/templates/travel-concierge/tools/cancel_ticket.ts +16 -0
- package/dist/templates/travel-concierge/tools/complete_or_escalate.ts +7 -0
- package/dist/templates/travel-concierge/tools/confirm_action.ts +7 -0
- package/dist/templates/travel-concierge/tools/lookup_booking.ts +35 -0
- package/dist/templates/travel-concierge/tools/search_car_rentals.ts +33 -0
- package/dist/templates/travel-concierge/tools/search_excursions.ts +37 -0
- package/dist/templates/travel-concierge/tools/search_flights.ts +43 -0
- package/dist/templates/travel-concierge/tools/search_hotels.ts +36 -0
- package/dist/templates/travel-concierge/tools/to_car_rental_assistant.ts +11 -0
- package/dist/templates/travel-concierge/tools/to_excursion_assistant.ts +11 -0
- package/dist/templates/travel-concierge/tools/to_flight_assistant.ts +11 -0
- package/dist/templates/travel-concierge/tools/to_hotel_assistant.ts +11 -0
- package/dist/templates/travel-concierge/tools/update_ticket.ts +22 -0
- package/dist/templates/web-researcher/agent.ts +0 -2
- package/dist/templates/web-researcher/system-prompt.md +10 -0
- package/dist/{test-2LWBcXvY.mjs → test-B6ZBxSpk.mjs} +2 -2
- package/dist/typecheck.mjs +17 -15
- package/dist/worker-bundler-CIdDhZ0c.mjs +398 -0
- package/dist/worker-bundler.d.ts +14 -0
- package/dist/worker-bundler.mjs +1 -108
- package/dist/workflow-B-O97AqI.mjs +125 -0
- package/dist/workflow-bundler.d.ts +133 -0
- package/dist/workflow.d.ts +67 -0
- package/package.json +13 -9
- package/dist/build-DQJ1ZSm9.mjs +0 -39
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
2
2
|
|
|
3
|
-
import type { ToolFailure } from "@alexkroman1/aai";
|
|
4
|
-
import { pushCapped,
|
|
3
|
+
import type { DeepReadonly, ToolFailure } from "@alexkroman1/aai";
|
|
4
|
+
import { pushCapped, sessionSlot } from "@alexkroman1/aai";
|
|
5
5
|
|
|
6
6
|
export const SEVERITIES = ["critical", "urgent", "moderate", "minor"] as const;
|
|
7
7
|
export type Severity = (typeof SEVERITIES)[number];
|
|
@@ -101,7 +101,7 @@ export interface IncidentSummary {
|
|
|
101
101
|
location: string;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export function incidentSummary(inc: Incident): IncidentSummary {
|
|
104
|
+
export function incidentSummary(inc: DeepReadonly<Incident>): IncidentSummary {
|
|
105
105
|
return { id: inc.id, severity: inc.severity, status: inc.status, location: inc.location };
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -114,7 +114,7 @@ export interface DashboardView {
|
|
|
114
114
|
/** The `syncState` projection — the whole contract with client.tsx. Takes the
|
|
115
115
|
* board itself, not the slot: `dispatchSlot.projection` supplies a real one
|
|
116
116
|
* even before the first tool call. */
|
|
117
|
-
export function dashboardView(state:
|
|
117
|
+
export function dashboardView(state: FrozenDispatchState): DashboardView {
|
|
118
118
|
return {
|
|
119
119
|
systemAlertLevel: state.alertLevel,
|
|
120
120
|
incidents: Object.values(state.incidents).map(incidentSummary),
|
|
@@ -162,9 +162,9 @@ export function createDefaultState(): DispatchState {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// ─── State helpers ───────────────────────────────────────────────────────────
|
|
165
|
-
// The dispatch board lives in `
|
|
166
|
-
//
|
|
167
|
-
//
|
|
165
|
+
// The dispatch board lives in one `sessionSlot`, keyed per session — sessions
|
|
166
|
+
// must not see each other's incidents, and a slot gives that isolation by
|
|
167
|
+
// construction.
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
170
|
* Growth caps. The whole dispatch state is one object whose summaries feed
|
|
@@ -186,12 +186,22 @@ function pruneState(state: DispatchState): void {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
|
-
* The session's dispatch board, as one typed slot
|
|
189
|
+
* The session's dispatch board, as one typed slot.
|
|
190
190
|
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
191
|
+
* Every tool here is declared through the slot rather than reaching for it from
|
|
192
|
+
* inside a `tool()` body, and WHICH HALF is the whole decision: `updateTool`
|
|
193
|
+
* runs the body inside the mutation window and hands it a draft that is stored
|
|
194
|
+
* when the body returns, `tool` hands it the deep-frozen stored value. That
|
|
195
|
+
* makes "does this tool write?" a property of the declaration a reader can see,
|
|
196
|
+
* and choosing wrong a compile error rather than a `TypeError` on the first
|
|
197
|
+
* call.
|
|
198
|
+
*
|
|
199
|
+
* The window is SYNCHRONOUS, which is what makes a read-modify-write atomic
|
|
200
|
+
* with no lock — the LLM loop runs a step's tool calls concurrently. It does
|
|
201
|
+
* NOT serialize anything (an earlier version of this comment claimed it did):
|
|
202
|
+
* there is nothing to serialize, because no other JS turn can interleave with
|
|
203
|
+
* a synchronous body. `updateTool` is what enforces the rule, refusing a
|
|
204
|
+
* thenable body by name.
|
|
195
205
|
*
|
|
196
206
|
* `after` is the bookkeeping every mutating tool needs and none of them should
|
|
197
207
|
* have to remember — pruning resolved incidents, and recalculating the alert
|
|
@@ -205,7 +215,16 @@ export const dispatchSlot = sessionSlot("dispatch", createDefaultState, {
|
|
|
205
215
|
},
|
|
206
216
|
});
|
|
207
217
|
|
|
208
|
-
|
|
218
|
+
/**
|
|
219
|
+
* The board as a READ hands it out: deep-frozen, and typed to say so.
|
|
220
|
+
*
|
|
221
|
+
* The pure helpers below take this rather than {@link DispatchState}, which is
|
|
222
|
+
* the widening a deep-readonly slot forces and the reason it is worth doing: a
|
|
223
|
+
* mutable board still satisfies it, so a helper called with an `updateTool`
|
|
224
|
+
* draft is unaffected, while a helper that WOULD have mutated stops compiling
|
|
225
|
+
* instead of throwing at its first call in production.
|
|
226
|
+
*/
|
|
227
|
+
export type FrozenDispatchState = DeepReadonly<DispatchState>;
|
|
209
228
|
|
|
210
229
|
// ─── Incident helpers ────────────────────────────────────────────────────────
|
|
211
230
|
|
|
@@ -237,7 +256,20 @@ export function createIncident(state: DispatchState, overrides: Partial<Incident
|
|
|
237
256
|
return incident;
|
|
238
257
|
}
|
|
239
258
|
|
|
240
|
-
|
|
259
|
+
/**
|
|
260
|
+
* One incident by id, or the failure the model should read.
|
|
261
|
+
*
|
|
262
|
+
* Generic over the incident's own type rather than pinned to {@link Incident},
|
|
263
|
+
* so ONE lookup serves both halves of the slot: a mutating tool passes its
|
|
264
|
+
* draft and gets a mutable incident back to change, while `incident_get` passes
|
|
265
|
+
* what `dispatchSlot.tool` handed it — deep-frozen — and gets a readonly one.
|
|
266
|
+
* Pinning it would have made the read path the odd one out, and its way out
|
|
267
|
+
* would have been a cast.
|
|
268
|
+
*/
|
|
269
|
+
export function findIncident<I extends DeepReadonly<Incident>>(
|
|
270
|
+
state: { readonly incidents: { readonly [id: string]: I } },
|
|
271
|
+
incidentId: string,
|
|
272
|
+
): I | ToolFailure {
|
|
241
273
|
return state.incidents[incidentId] ?? { error: `Incident ${incidentId} not found` };
|
|
242
274
|
}
|
|
243
275
|
|
|
@@ -251,17 +283,19 @@ export function logEvent(inc: Incident, event: string): void {
|
|
|
251
283
|
}
|
|
252
284
|
|
|
253
285
|
/** Minutes since the incident was created, rounded. */
|
|
254
|
-
export function incidentAgeMinutes(inc: Incident): number {
|
|
286
|
+
export function incidentAgeMinutes(inc: DeepReadonly<Incident>): number {
|
|
255
287
|
return Math.round((Date.now() - inc.createdAt) / 60_000);
|
|
256
288
|
}
|
|
257
289
|
|
|
258
290
|
/** A resource as tool results describe it to the LLM. */
|
|
259
|
-
export function resourceBrief(r: Resource): {
|
|
291
|
+
export function resourceBrief(r: DeepReadonly<Resource>): {
|
|
260
292
|
callsign: string;
|
|
261
293
|
type: Resource["type"];
|
|
262
294
|
capabilities: string[];
|
|
263
295
|
} {
|
|
264
|
-
|
|
296
|
+
// `capabilities` is COPIED: a brief is a fresh object handed to the LLM, and
|
|
297
|
+
// the source list belongs either to a frozen slot value or to a live draft.
|
|
298
|
+
return { callsign: r.callsign, type: r.type, capabilities: [...r.capabilities] };
|
|
265
299
|
}
|
|
266
300
|
|
|
267
301
|
/**
|
|
@@ -269,7 +303,7 @@ export function resourceBrief(r: Resource): {
|
|
|
269
303
|
* resources have been released (and possibly reassigned), so escalating,
|
|
270
304
|
* re-resolving, or dispatching to it would corrupt resource assignments.
|
|
271
305
|
*/
|
|
272
|
-
export function assertNotResolved(inc: Incident
|
|
306
|
+
export function assertNotResolved(inc: DeepReadonly<Incident>, action: string): ToolFailure | null {
|
|
273
307
|
if (inc.status === "resolved") {
|
|
274
308
|
return {
|
|
275
309
|
error: `Incident ${inc.id} is resolved — cannot ${action}. Create a new incident if the situation has reopened.`,
|
|
@@ -575,7 +609,7 @@ export function recommendResources(
|
|
|
575
609
|
/** Fraction of resources not currently available, 0–1. The alert level and
|
|
576
610
|
* the dashboard's displayed utilization both derive from this, so they can
|
|
577
611
|
* never disagree about what "utilization" means. */
|
|
578
|
-
export function resourceUtilization(state:
|
|
612
|
+
export function resourceUtilization(state: FrozenDispatchState): number {
|
|
579
613
|
const available = state.resources.filter((r) => r.status === "available").length;
|
|
580
614
|
return 1 - available / state.resources.length;
|
|
581
615
|
}
|
|
@@ -1,27 +1,25 @@
|
|
|
1
|
-
import { isToolFailure
|
|
1
|
+
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { dispatchSlot, findIncident, logEvent } from "../shared.ts";
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export default dispatchSlot.updateTool({
|
|
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(),
|
|
11
11
|
}),
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (isToolFailure(inc)) return inc;
|
|
12
|
+
execute(args, state) {
|
|
13
|
+
const inc = findIncident(state, args.incidentId);
|
|
14
|
+
if (isToolFailure(inc)) return inc;
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const entry = args.source ? `[${args.source}] ${args.note}` : args.note;
|
|
17
|
+
logEvent(inc, entry);
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
19
|
+
return {
|
|
20
|
+
incidentId: args.incidentId,
|
|
21
|
+
noteAdded: entry,
|
|
22
|
+
timelineEntries: inc.timeline.length,
|
|
23
|
+
};
|
|
26
24
|
},
|
|
27
25
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { tool } from "@alexkroman1/aai";
|
|
2
1
|
import { z } from "zod";
|
|
3
2
|
import {
|
|
4
3
|
calculateTriageScore,
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
resourceBrief,
|
|
12
11
|
} from "../shared.ts";
|
|
13
12
|
|
|
14
|
-
export
|
|
13
|
+
export default dispatchSlot.updateTool({
|
|
15
14
|
description: "Create a new incident from an incoming emergency call.",
|
|
16
15
|
inputSchema: z.object({
|
|
17
16
|
location: z.string().max(300).describe("Address or location description"),
|
|
@@ -30,50 +29,48 @@ export const incidentCreate = tool({
|
|
|
30
29
|
.describe("Known hazards: fire, chemical, electrical, structural, weapons")
|
|
31
30
|
.optional(),
|
|
32
31
|
}),
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
32
|
+
execute(args, state) {
|
|
33
|
+
const recSeverity = recommendSeverity(args.description);
|
|
34
|
+
const recType = recommendType(args.description);
|
|
35
|
+
const triageScore = calculateTriageScore(
|
|
36
|
+
recSeverity,
|
|
37
|
+
recType,
|
|
38
|
+
args.estimatedCasualties ?? 0,
|
|
39
|
+
args.hazards?.length ?? 0,
|
|
40
|
+
);
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
42
|
+
const incident = createIncident(state, {
|
|
43
|
+
type: recType,
|
|
44
|
+
severity: recSeverity,
|
|
45
|
+
location: args.location,
|
|
46
|
+
description: args.description,
|
|
47
|
+
callerName: args.callerName ?? "Unknown",
|
|
48
|
+
callerPhone: args.callerPhone ?? "Unknown",
|
|
49
|
+
triageScore,
|
|
50
|
+
timeline: [{ time: Date.now(), event: `Incident created: ${args.description}` }],
|
|
51
|
+
casualties: {
|
|
52
|
+
confirmed: 0,
|
|
53
|
+
estimated: args.estimatedCasualties ?? 0,
|
|
54
|
+
treated: 0,
|
|
55
|
+
},
|
|
56
|
+
hazards: args.hazards ?? [],
|
|
57
|
+
});
|
|
58
|
+
const id = incident.id;
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const protocols = getApplicableProtocols(recType, recSeverity);
|
|
61
|
+
const recommended = recommendResources(recType, recSeverity, state);
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
63
|
+
return {
|
|
64
|
+
incidentId: id,
|
|
65
|
+
recommendedSeverity: recSeverity,
|
|
66
|
+
recommendedType: recType,
|
|
67
|
+
triageScore,
|
|
68
|
+
applicableProtocols: protocols.map((p) => p.name),
|
|
69
|
+
recommendedResources: recommended.map(resourceBrief),
|
|
70
|
+
message:
|
|
71
|
+
recSeverity === "critical"
|
|
72
|
+
? `PRIORITY ONE — ${id} created. Immediate dispatch recommended. ${protocols.length} protocol(s) applicable.`
|
|
73
|
+
: `${id} created. Triage score ${triageScore}. ${recommended.length} resource(s) recommended.`,
|
|
74
|
+
};
|
|
78
75
|
},
|
|
79
76
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isToolFailure
|
|
1
|
+
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import {
|
|
4
4
|
assertNotResolved,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
recommendResources,
|
|
10
10
|
} from "../shared.ts";
|
|
11
11
|
|
|
12
|
-
export
|
|
12
|
+
export default dispatchSlot.updateTool({
|
|
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"),
|
|
@@ -20,69 +20,67 @@ export const incidentEscalate = tool({
|
|
|
20
20
|
.optional(),
|
|
21
21
|
newSeverity: z.enum(["critical", "urgent"]).describe("Escalated severity level").optional(),
|
|
22
22
|
}),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (blocked) return blocked;
|
|
23
|
+
execute(args, state) {
|
|
24
|
+
const inc = findIncident(state, args.incidentId);
|
|
25
|
+
if (isToolFailure(inc)) return inc;
|
|
26
|
+
const blocked = assertNotResolved(inc, "escalate");
|
|
27
|
+
if (blocked) return blocked;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
inc.escalationLevel++;
|
|
30
|
+
if (args.newSeverity) inc.severity = args.newSeverity;
|
|
31
|
+
inc.status = "escalated";
|
|
32
|
+
logEvent(inc, `ESCALATED (Level ${inc.escalationLevel}): ${args.reason}`);
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
inc.triageScore = calculateTriageScore(
|
|
64
|
-
inc.severity,
|
|
65
|
-
inc.type,
|
|
66
|
-
inc.casualties.estimated,
|
|
67
|
-
inc.hazards.length,
|
|
34
|
+
if (args.requestMutualAid) {
|
|
35
|
+
logEvent(inc, "Mutual aid requested from neighboring jurisdictions");
|
|
36
|
+
// Counter-based ids/callsigns: Date.now() collides across rapid
|
|
37
|
+
// escalations, and duplicate callsigns break dispatch-by-callsign.
|
|
38
|
+
const medicN = ++state.mutualAidCounter;
|
|
39
|
+
const engineN = ++state.mutualAidCounter;
|
|
40
|
+
state.resources.push(
|
|
41
|
+
{
|
|
42
|
+
id: `MA-${medicN}`,
|
|
43
|
+
type: "ambulance",
|
|
44
|
+
callsign: `Mutual-Aid-Medic-${medicN}`,
|
|
45
|
+
status: "available",
|
|
46
|
+
assignedIncident: null,
|
|
47
|
+
eta: null,
|
|
48
|
+
capabilities: ["als"],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: `MA-${engineN}`,
|
|
52
|
+
type: "fire_engine",
|
|
53
|
+
callsign: `Mutual-Aid-Engine-${engineN}`,
|
|
54
|
+
status: "available",
|
|
55
|
+
assignedIncident: null,
|
|
56
|
+
eta: null,
|
|
57
|
+
capabilities: ["structural"],
|
|
58
|
+
},
|
|
68
59
|
);
|
|
60
|
+
}
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
inc.triageScore = calculateTriageScore(
|
|
63
|
+
inc.severity,
|
|
64
|
+
inc.type,
|
|
65
|
+
inc.casualties.estimated,
|
|
66
|
+
inc.hazards.length,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const additionalResources = recommendResources(inc.type, inc.severity, state).filter(
|
|
70
|
+
(r) => !inc.assignedResources.includes(r.id),
|
|
71
|
+
);
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
});
|
|
73
|
+
return {
|
|
74
|
+
incidentId: args.incidentId,
|
|
75
|
+
escalationLevel: inc.escalationLevel,
|
|
76
|
+
newSeverity: inc.severity,
|
|
77
|
+
newTriageScore: inc.triageScore,
|
|
78
|
+
mutualAidRequested: args.requestMutualAid ?? false,
|
|
79
|
+
additionalResourcesAvailable: additionalResources.map((r) => ({
|
|
80
|
+
callsign: r.callsign,
|
|
81
|
+
type: r.type,
|
|
82
|
+
})),
|
|
83
|
+
message: `ESCALATION CONFIRMED — ${args.incidentId} now Level ${inc.escalationLevel}. ${additionalResources.length} additional resource(s) available for dispatch.`,
|
|
84
|
+
};
|
|
87
85
|
},
|
|
88
86
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isToolFailure
|
|
1
|
+
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import {
|
|
4
4
|
dispatchSlot,
|
|
@@ -7,13 +7,12 @@ import {
|
|
|
7
7
|
incidentAgeMinutes,
|
|
8
8
|
} from "../shared.ts";
|
|
9
9
|
|
|
10
|
-
export
|
|
10
|
+
export default dispatchSlot.tool({
|
|
11
11
|
description: "Get full details on a specific incident including timeline and assigned resources.",
|
|
12
12
|
inputSchema: z.object({
|
|
13
13
|
incidentId: z.string().max(20).describe("The incident ID"),
|
|
14
14
|
}),
|
|
15
|
-
|
|
16
|
-
const state = dispatchSlot.get(ctx);
|
|
15
|
+
execute(args, state) {
|
|
17
16
|
const inc = findIncident(state, args.incidentId);
|
|
18
17
|
if (isToolFailure(inc)) return inc;
|
|
19
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isToolFailure
|
|
1
|
+
import { isToolFailure } from "@alexkroman1/aai";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import {
|
|
4
4
|
assertNotResolved,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
SEVERITIES,
|
|
13
13
|
} from "../shared.ts";
|
|
14
14
|
|
|
15
|
-
export
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
55
|
+
const protocols = getApplicableProtocols(inc.type, inc.severity);
|
|
56
|
+
const recommended = recommendResources(inc.type, inc.severity, state);
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
});
|