@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
|
@@ -6,28 +6,31 @@
|
|
|
6
6
|
},
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "aai dev",
|
|
9
|
+
"prestart": "aai build --skip-tests",
|
|
9
10
|
"start": "node server.mjs",
|
|
10
11
|
"build": "aai build",
|
|
11
12
|
"test": "aai test",
|
|
12
13
|
"publish:agent": "aai publish"
|
|
13
14
|
},
|
|
14
15
|
"dependencies": {
|
|
15
|
-
"@alexkroman1/aai": "^
|
|
16
|
-
"@alexkroman1/aai-ui": "^
|
|
16
|
+
"@alexkroman1/aai": "^6.1.0",
|
|
17
|
+
"@alexkroman1/aai-ui": "^6.1.0",
|
|
18
|
+
"@workflow/world-postgres": "4.3.3",
|
|
17
19
|
"react": "^19.2.8",
|
|
18
20
|
"react-dom": "^19.2.8",
|
|
19
21
|
"tailwindcss": "^4.0.0",
|
|
22
|
+
"workflow": "4.8.2",
|
|
20
23
|
"zod": "^4.4.3"
|
|
21
24
|
},
|
|
22
25
|
"devDependencies": {
|
|
23
|
-
"@alexkroman1/aai-cli": "^
|
|
26
|
+
"@alexkroman1/aai-cli": "^6.1.0",
|
|
24
27
|
"@tailwindcss/vite": "^4.3.3",
|
|
25
|
-
"@types/node": "^26.
|
|
26
|
-
"@types/react": "^19.2.
|
|
27
|
-
"@types/react-dom": "^19.2.
|
|
28
|
-
"@vitejs/plugin-react": "^6.0.
|
|
28
|
+
"@types/node": "^26.2.0",
|
|
29
|
+
"@types/react": "^19.2.18",
|
|
30
|
+
"@types/react-dom": "^19.2.4",
|
|
31
|
+
"@vitejs/plugin-react": "^6.0.5",
|
|
29
32
|
"typescript": "^7.0.2",
|
|
30
|
-
"vite": "^8.1
|
|
33
|
+
"vite": "^8.2.1",
|
|
31
34
|
"vitest": "^4.1.10"
|
|
32
35
|
}
|
|
33
36
|
}
|
|
@@ -7,9 +7,17 @@
|
|
|
7
7
|
# build script without this entry. pnpm 10 reads `onlyBuiltDependencies`;
|
|
8
8
|
# pnpm 11 renamed it to `allowBuilds` and ignores the old key, so both are
|
|
9
9
|
# declared. This file also marks the project as its own pnpm workspace root.
|
|
10
|
+
# `@swc/core` and `cbor-extract` arrive TRANSITIVELY, through the `workflow`
|
|
11
|
+
# dependency the DevKit templates need. pnpm 11 makes an undeclared build script
|
|
12
|
+
# a hard error (`ERR_PNPM_IGNORED_BUILDS`), so leaving them out fails the install
|
|
13
|
+
# — which is the very first thing `aai init` does after writing these files.
|
|
10
14
|
onlyBuiltDependencies:
|
|
15
|
+
- "@swc/core"
|
|
16
|
+
- cbor-extract
|
|
11
17
|
- esbuild
|
|
12
18
|
allowBuilds:
|
|
19
|
+
"@swc/core": true
|
|
20
|
+
cbor-extract: true
|
|
13
21
|
esbuild: true
|
|
14
22
|
|
|
15
23
|
# Exempt our own packages from pnpm's release-age quarantine, and ONLY ours.
|
package/dist/scaffold/server.mjs
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
// Self-hosted entrypoint — this is what `npm start` runs.
|
|
2
2
|
//
|
|
3
3
|
// It serves the agent over HTTP + WebSocket from your own Node process: no
|
|
4
|
-
// platform account, no
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// platform account, no managed anything. `aai dev` is the development
|
|
5
|
+
// counterpart (file watching, Vite, a browser that opens itself); this file is
|
|
6
|
+
// the deployment.
|
|
7
7
|
//
|
|
8
8
|
// npm start # http://127.0.0.1:3000
|
|
9
9
|
// PORT=8080 HOST=0.0.0.0 npm start # bind every interface, e.g. in a container
|
|
10
10
|
//
|
|
11
11
|
// Anything that can run Node can host it: copy the project, install
|
|
12
|
-
// dependencies, provide the secrets, run
|
|
13
|
-
// — `aai dev`, `aai publish` and the managed platform never read it.
|
|
12
|
+
// dependencies, provide the secrets, run `npm start`. Deleting this file costs
|
|
13
|
+
// nothing — `aai dev`, `aai publish` and the managed platform never read it.
|
|
14
14
|
|
|
15
|
-
import { existsSync
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
16
|
import { readFile } from "node:fs/promises";
|
|
17
|
-
import { registerHooks } from "node:module";
|
|
18
17
|
import path from "node:path";
|
|
19
|
-
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
20
19
|
import { parseEnv } from "node:util";
|
|
21
20
|
import { createAgentServer, withHostCredentialFallback } from "@alexkroman1/aai/runtime";
|
|
22
21
|
import { defaultClientDir } from "@alexkroman1/aai-ui/client-dir";
|
|
@@ -24,56 +23,38 @@ import { defaultClientDir } from "@alexkroman1/aai-ui/client-dir";
|
|
|
24
23
|
const root = path.dirname(fileURLToPath(import.meta.url));
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* The built agent — `.aai/worker.mjs`, produced by `aai build`, which the
|
|
27
|
+
* `prestart` script runs for you. It is the SAME artifact `aai publish` uploads
|
|
28
|
+
* and the managed platform runs, so a self-hosted agent and a deployed one
|
|
29
|
+
* cannot behave differently.
|
|
29
30
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* Loading the build rather than `agent.ts` directly is what makes `tools/`
|
|
32
|
+
* work. A tool is registered by EXISTING — its file name is the name the model
|
|
33
|
+
* calls, and nothing anywhere lists them — and the only place a directory can
|
|
34
|
+
* be turned into modules is where the bundle is assembled: a deployed agent is
|
|
35
|
+
* handed one ESM string and has no filesystem to scan. So the bundler
|
|
36
|
+
* enumerates `tools/` and emits the imports, and every loader that skips it
|
|
37
|
+
* would serve an agent with no tools at all.
|
|
36
38
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* It also settles two things the bundler already resolves, and this file used
|
|
40
|
+
* to re-implement with `node:module` hooks: `import prompt from
|
|
41
|
+
* "./system-prompt.md?raw"` (a Vite convention — Node looks for a file
|
|
42
|
+
* literally named `system-prompt.md?raw`) and `import data from "./data.json"`
|
|
43
|
+
* with no import attribute (TypeScript's `resolveJsonModule` allows it, Node
|
|
44
|
+
* requires `with { type: "json" }`). Both are inlined into the bundle, so
|
|
45
|
+
* there is nothing left to teach Node.
|
|
41
46
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return nextResolve(specifier, context);
|
|
54
|
-
},
|
|
55
|
-
load(url, context, nextLoad) {
|
|
56
|
-
const asRaw = url.endsWith("?raw");
|
|
57
|
-
const asBareJson = url.endsWith(".json") && context.importAttributes?.type !== "json";
|
|
58
|
-
if (!(asRaw || asBareJson)) return nextLoad(url, context);
|
|
59
|
-
const text = readFileSync(fileURLToPath(asRaw ? url.slice(0, -"?raw".length) : url), "utf-8");
|
|
60
|
-
return {
|
|
61
|
-
format: "module",
|
|
62
|
-
// `export default <literal>` for both: a JSON document is already a
|
|
63
|
-
// valid JS expression, and JSON.stringify makes any file safe to embed
|
|
64
|
-
// as a string. Emitting `format: "json"` instead would put the import
|
|
65
|
-
// back under the attribute check this exists to satisfy.
|
|
66
|
-
source: `export default ${asRaw ? JSON.stringify(text) : text};`,
|
|
67
|
-
shortCircuit: true,
|
|
68
|
-
};
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Imported dynamically, and this is load-bearing: static `import` statements
|
|
73
|
-
// are hoisted and evaluated BEFORE any statement in this file, so an
|
|
74
|
-
// `import agent from "./agent.ts"` at the top would load the agent — and every
|
|
75
|
-
// `?raw` import inside it — before the hooks above were ever registered.
|
|
76
|
-
const { default: agent } = await import("./agent.ts");
|
|
47
|
+
const workerPath = path.join(root, ".aai", "worker.mjs");
|
|
48
|
+
if (!existsSync(workerPath)) {
|
|
49
|
+
console.error(
|
|
50
|
+
`No built agent at ${path.relative(root, workerPath)}.\n` +
|
|
51
|
+
"Run `npm run build` (or `aai build`) first — `npm start` normally does it for you.",
|
|
52
|
+
);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
// A file: URL rather than a relative specifier, so the path is correct on
|
|
56
|
+
// Windows, where a bare POSIX-looking path is not a valid module specifier.
|
|
57
|
+
const { default: agent } = await import(pathToFileURL(workerPath).href);
|
|
77
58
|
|
|
78
59
|
/** Parse a dotenv-syntax file into a record; `{}` when it does not exist. */
|
|
79
60
|
async function readEnvFile(file) {
|
|
@@ -116,8 +97,8 @@ async function resolveAgentEnv() {
|
|
|
116
97
|
|
|
117
98
|
/**
|
|
118
99
|
* Static assets served at `/`: this project's own UI once `client.tsx` has been
|
|
119
|
-
* built (`
|
|
120
|
-
* default client that ships inside @alexkroman1/aai-ui.
|
|
100
|
+
* built (the same `aai build` leaves it in `.aai/client`), otherwise the
|
|
101
|
+
* prebuilt default client that ships inside @alexkroman1/aai-ui.
|
|
121
102
|
*/
|
|
122
103
|
function resolveClientDir() {
|
|
123
104
|
const built = path.join(root, ".aai", "client");
|
|
@@ -130,6 +111,20 @@ function resolveClientDir() {
|
|
|
130
111
|
|
|
131
112
|
const env = await resolveAgentEnv();
|
|
132
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Where THIS server is reachable from outside — `PUBLIC_URL`, e.g.
|
|
116
|
+
* `https://agent.example.com`. Set it whenever a durable workflow has to hand a
|
|
117
|
+
* URL to somebody else: `ctx.workflows.publicWebhookUrl(token)` is built from it,
|
|
118
|
+
* and without it that call throws rather than minting a `http://localhost:3000`
|
|
119
|
+
* URL that a payment provider will try, days later, and fail.
|
|
120
|
+
*
|
|
121
|
+
* Nothing else reads it, so it is not a startup requirement: an agent with no
|
|
122
|
+
* webhooks needs no value here. It is deliberately NOT derived from `PORT`/`HOST`
|
|
123
|
+
* — those describe the socket this process binds, which behind a reverse proxy is
|
|
124
|
+
* not what the outside world dials.
|
|
125
|
+
*/
|
|
126
|
+
const publicUrl = process.env.PUBLIC_URL?.trim();
|
|
127
|
+
|
|
133
128
|
const server = createAgentServer({
|
|
134
129
|
agent,
|
|
135
130
|
env,
|
|
@@ -138,6 +133,7 @@ const server = createAgentServer({
|
|
|
138
133
|
// ASSEMBLYAI_API_KEY to a container. Anything in `env` still wins.
|
|
139
134
|
providerEnv: withHostCredentialFallback(env),
|
|
140
135
|
clientDir: resolveClientDir(),
|
|
136
|
+
...(publicUrl ? { publicUrl } : {}),
|
|
141
137
|
});
|
|
142
138
|
|
|
143
139
|
// Loopback by default: this server has no request authentication of its own,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as ok, n as fail } from "./_output-
|
|
2
|
+
import { a as ok, n as fail } from "./_output-CKkmWs7i.mjs";
|
|
3
3
|
import { n as log, s as unwrapCancel } from "./_ui-u7T4YooX.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { a as isStringArray, i as checkedResponse } from "./_api-client-LgLksMhN.mjs";
|
|
5
|
+
import { t as secretRequest } from "./_slug-api-D2heILuC.mjs";
|
|
6
|
+
import { isRecord } from "@alexkroman1/aai/utils";
|
|
5
7
|
import * as p from "@clack/prompts";
|
|
6
8
|
import { text } from "node:stream/consumers";
|
|
7
9
|
//#region secret.ts
|
|
@@ -46,7 +48,8 @@ async function executeSecretDelete(cwd, name, server) {
|
|
|
46
48
|
return ok({ name });
|
|
47
49
|
}
|
|
48
50
|
async function executeSecretList(cwd, server) {
|
|
49
|
-
const { data
|
|
51
|
+
const { data, target } = await secretRequest(cwd, "", { action: "secret" }, server);
|
|
52
|
+
const { vars } = checkedResponse(data, (value) => isRecord(value) && isStringArray(value.vars), `the secret list for ${target}`);
|
|
50
53
|
if (vars.length === 0) log.info("No secrets set. Use `aai secret put <name>` to add one.");
|
|
51
54
|
else {
|
|
52
55
|
log.message(`${vars.length} secret${vars.length === 1 ? "" : "s"}:`);
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as ok, n as fail } from "./_output-
|
|
2
|
+
import { a as ok, n as fail } from "./_output-CKkmWs7i.mjs";
|
|
3
3
|
import { n as log } from "./_ui-u7T4YooX.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { i as checkedResponse } from "./_api-client-LgLksMhN.mjs";
|
|
5
|
+
import { n as slugRequest } from "./_slug-api-D2heILuC.mjs";
|
|
6
|
+
import { isRecord } from "@alexkroman1/aai/utils";
|
|
5
7
|
import * as p from "@clack/prompts";
|
|
6
8
|
//#region storage.ts
|
|
9
|
+
/**
|
|
10
|
+
* The storage route's answer, CHECKED — every caller here reads `enabled` and
|
|
11
|
+
* a body without it reported "Storage is disabled for <slug>" (and returned
|
|
12
|
+
* `enabled: undefined` to a script) for a server that never said so. See
|
|
13
|
+
* `checkedResponse`.
|
|
14
|
+
*/
|
|
7
15
|
async function storageRequest(cwd, init, server) {
|
|
8
|
-
|
|
16
|
+
const { data, slug } = await slugRequest(cwd, "/storage", {
|
|
9
17
|
...init,
|
|
10
18
|
action: "storage"
|
|
11
19
|
}, server);
|
|
20
|
+
return {
|
|
21
|
+
enabled: checkedResponse(data, (value) => isRecord(value) && typeof value.enabled === "boolean", `the storage route for ${slug}`).enabled,
|
|
22
|
+
slug
|
|
23
|
+
};
|
|
12
24
|
}
|
|
13
25
|
async function executeStorageStatus(cwd, server) {
|
|
14
|
-
const {
|
|
26
|
+
const { enabled, slug } = await storageRequest(cwd, void 0, server);
|
|
15
27
|
if (enabled) log.info(`Storage is enabled for ${slug}`);
|
|
16
28
|
else log.info(`Storage is disabled for ${slug}. Use \`aai storage enable\` to turn it on.`);
|
|
17
29
|
return ok({
|
|
@@ -20,7 +32,7 @@ async function executeStorageStatus(cwd, server) {
|
|
|
20
32
|
});
|
|
21
33
|
}
|
|
22
34
|
async function executeStorageEnable(cwd, server) {
|
|
23
|
-
const {
|
|
35
|
+
const { enabled, slug } = await storageRequest(cwd, { method: "POST" }, server);
|
|
24
36
|
log.success(`Storage enabled for ${slug}`);
|
|
25
37
|
log.info("Tool code can now use ctx.db.query(sql, params).");
|
|
26
38
|
return ok({
|
|
@@ -43,7 +55,7 @@ async function executeStorageDisable(cwd, opts = {}) {
|
|
|
43
55
|
return fail("cancelled", "Disable cancelled");
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
|
-
const {
|
|
58
|
+
const { enabled, slug } = await storageRequest(cwd, { method: "DELETE" }, opts.server);
|
|
47
59
|
log.success(`Storage disabled for ${slug} — database schema and data dropped`);
|
|
48
60
|
return ok({
|
|
49
61
|
slug,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as ok, t as CliError } from "./_output-
|
|
2
|
+
import { a as ok, t as CliError } from "./_output-CKkmWs7i.mjs";
|
|
3
3
|
import { n as log, t as fmtUrl } from "./_ui-u7T4YooX.mjs";
|
|
4
|
-
import { s as updateProjectConfig } from "./_config-
|
|
5
|
-
import { t as resolveServerEnv } from "./_server-common-
|
|
6
|
-
import {
|
|
7
|
-
import { layerScaffold } from "./_templates-
|
|
8
|
-
import { n as apiRequest } from "./_api-client-
|
|
9
|
-
import { a as publishStudioProject, i as projectNameFromDir, n as fetchStudioProject, o as pushStudioSource, r as listStudioProjects, s as studioProjectUrl, t as collectSourceFiles } from "./_studio-
|
|
4
|
+
import { s as updateProjectConfig } from "./_config-D_s09e7g.mjs";
|
|
5
|
+
import { t as resolveServerEnv } from "./_server-common-6e0QI4mq.mjs";
|
|
6
|
+
import { a as resolveDeployTarget } from "./_agent-vGW5SBnX.mjs";
|
|
7
|
+
import { layerScaffold } from "./_templates-iDGjGiPf.mjs";
|
|
8
|
+
import { i as checkedResponse, n as apiRequest } from "./_api-client-LgLksMhN.mjs";
|
|
9
|
+
import { a as publishStudioProject, i as projectNameFromDir, n as fetchStudioProject, o as pushStudioSource, r as listStudioProjects, s as studioProjectUrl, t as collectSourceFiles } from "./_studio-zAJycZ8j.mjs";
|
|
10
10
|
import path from "node:path";
|
|
11
|
+
import { isRecord } from "@alexkroman1/aai/utils";
|
|
11
12
|
import { mkdir, readdir, writeFile } from "node:fs/promises";
|
|
12
13
|
//#region studio.ts
|
|
13
14
|
/**
|
|
@@ -158,7 +159,7 @@ async function syncEnvSecrets(cwd, serverUrl, apiKey, project) {
|
|
|
158
159
|
}
|
|
159
160
|
async function executePublish(opts) {
|
|
160
161
|
if (!opts.skipTypecheck) {
|
|
161
|
-
const { assertTypechecks } = await import("./_typecheck-gate-
|
|
162
|
+
const { assertTypechecks } = await import("./_typecheck-gate-BXvUNnfs.mjs");
|
|
162
163
|
await assertTypechecks(opts.cwd);
|
|
163
164
|
}
|
|
164
165
|
const pushed = await pushProject(opts);
|
|
@@ -166,8 +167,7 @@ async function executePublish(opts) {
|
|
|
166
167
|
const hadSlug = pushed.slug !== void 0;
|
|
167
168
|
if (pushed.slug) await syncEnvSecrets(opts.cwd, serverUrl, apiKey, project);
|
|
168
169
|
log.step(`Publishing ${project} (builds in the project's sandbox)…`);
|
|
169
|
-
const result = await publishStudioProject(serverUrl, apiKey, project);
|
|
170
|
-
if (typeof result?.slug !== "string" || typeof result?.output !== "string") throw new CliError("bad_publish_response", `Unexpected response from the publish route at ${serverUrl}.`, "Check that --server points at an aai platform server, then try again.");
|
|
170
|
+
const result = checkedResponse(await publishStudioProject(serverUrl, apiKey, project), (value) => isRecord(value) && typeof value.slug === "string" && typeof value.output === "string", `the publish route at ${serverUrl}`);
|
|
171
171
|
if (result.output.trim()) log.message(result.output.trim());
|
|
172
172
|
await updateProjectConfig(opts.cwd, {
|
|
173
173
|
serverUrl,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { agent } from "@alexkroman1/aai";
|
|
2
|
-
import systemPrompt from "./system-prompt.md?raw";
|
|
3
2
|
|
|
4
3
|
export default agent({
|
|
5
4
|
name: "Coda",
|
|
6
|
-
systemPrompt,
|
|
7
5
|
greeting:
|
|
8
6
|
"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.",
|
|
9
7
|
builtinTools: ["run_code"],
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type { ToolContext } from "@alexkroman1/aai";
|
|
2
2
|
import { createToolContext } from "@alexkroman1/aai/testing";
|
|
3
3
|
import { describe, expect, test } from "vitest";
|
|
4
|
-
import { dispatchSlot
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
/** The dispatch board lives in
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
return { ctx: createToolContext<StateSlot>() };
|
|
17
|
-
}
|
|
4
|
+
import { dispatchSlot } from "./shared.ts";
|
|
5
|
+
import incidentCreate from "./tools/incident_create.ts";
|
|
6
|
+
import incidentEscalate from "./tools/incident_escalate.ts";
|
|
7
|
+
import incidentTriage from "./tools/incident_triage.ts";
|
|
8
|
+
import incidentUpdateStatus from "./tools/incident_update_status.ts";
|
|
9
|
+
import resourcesDispatch from "./tools/resources_dispatch.ts";
|
|
10
|
+
import resourcesUpdateStatus from "./tools/resources_update_status.ts";
|
|
11
|
+
|
|
12
|
+
/** The dispatch board lives in a session slot, and `createToolContext` gives
|
|
13
|
+
* each call its own slot store — so two contexts are two boards by
|
|
14
|
+
* construction. */
|
|
15
|
+
const makeCtx = (): ToolContext => createToolContext();
|
|
18
16
|
|
|
19
17
|
async function createIncidentFor(
|
|
20
18
|
ctx: ToolContext,
|
|
@@ -29,7 +27,7 @@ async function createIncidentFor(
|
|
|
29
27
|
|
|
30
28
|
describe("dispatch-center template", () => {
|
|
31
29
|
test("resolving an incident does not yank a reassigned unit off its new incident", async () => {
|
|
32
|
-
const
|
|
30
|
+
const ctx = makeCtx();
|
|
33
31
|
|
|
34
32
|
const inc1 = await createIncidentFor(ctx);
|
|
35
33
|
await resourcesDispatch.execute({ incidentId: inc1, callsigns: ["Medic-1"] }, ctx);
|
|
@@ -51,7 +49,7 @@ describe("dispatch-center template", () => {
|
|
|
51
49
|
});
|
|
52
50
|
|
|
53
51
|
test("callsigns: ['auto'] triggers auto-dispatch as the description promises", async () => {
|
|
54
|
-
const
|
|
52
|
+
const ctx = makeCtx();
|
|
55
53
|
const incidentId = await createIncidentFor(ctx, "cardiac arrest, patient not breathing");
|
|
56
54
|
|
|
57
55
|
const result = (await resourcesDispatch.execute({ incidentId, callsigns: ["auto"] }, ctx)) as {
|
|
@@ -64,7 +62,7 @@ describe("dispatch-center template", () => {
|
|
|
64
62
|
});
|
|
65
63
|
|
|
66
64
|
test("concurrent tool calls are serialized — no lost updates", async () => {
|
|
67
|
-
const
|
|
65
|
+
const ctx = makeCtx();
|
|
68
66
|
|
|
69
67
|
// Parallel tool calls in one LLM turn run concurrently. The per-session
|
|
70
68
|
// mutex in updateState makes each one run against the previous one's
|
|
@@ -102,7 +100,7 @@ describe("dispatch-center template", () => {
|
|
|
102
100
|
});
|
|
103
101
|
|
|
104
102
|
test("mutual-aid units get unique ids and callsigns across escalations", async () => {
|
|
105
|
-
const
|
|
103
|
+
const ctx = makeCtx();
|
|
106
104
|
const incidentId = await createIncidentFor(ctx);
|
|
107
105
|
|
|
108
106
|
await incidentEscalate.execute(
|
|
@@ -122,7 +120,7 @@ describe("dispatch-center template", () => {
|
|
|
122
120
|
});
|
|
123
121
|
|
|
124
122
|
test("resolved is terminal: no escalation, re-resolution, or dispatch", async () => {
|
|
125
|
-
const
|
|
123
|
+
const ctx = makeCtx();
|
|
126
124
|
const incidentId = await createIncidentFor(ctx);
|
|
127
125
|
await incidentUpdateStatus.execute({ incidentId, status: "resolved" }, ctx);
|
|
128
126
|
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import { agent } from "@alexkroman1/aai";
|
|
2
2
|
import { dashboardView, dispatchSlot } from "./shared.ts";
|
|
3
|
-
import systemPrompt from "./system-prompt.md?raw";
|
|
4
|
-
import { incidentAddNote } from "./tools/incident_add_note.ts";
|
|
5
|
-
import { incidentCreate } from "./tools/incident_create.ts";
|
|
6
|
-
import { incidentEscalate } from "./tools/incident_escalate.ts";
|
|
7
|
-
import { incidentGet } from "./tools/incident_get.ts";
|
|
8
|
-
import { incidentTriage } from "./tools/incident_triage.ts";
|
|
9
|
-
import { incidentUpdateStatus } from "./tools/incident_update_status.ts";
|
|
10
|
-
import { opsDashboard } from "./tools/ops_dashboard.ts";
|
|
11
|
-
import { opsProtocols } from "./tools/ops_protocols.ts";
|
|
12
|
-
import { opsRunScenario } from "./tools/ops_run_scenario.ts";
|
|
13
|
-
import { resourcesDispatch } from "./tools/resources_dispatch.ts";
|
|
14
|
-
import { resourcesGetAvailable } from "./tools/resources_get_available.ts";
|
|
15
|
-
import { resourcesUpdateStatus } from "./tools/resources_update_status.ts";
|
|
16
3
|
|
|
17
4
|
export default agent({
|
|
18
5
|
name: "Dispatch Command Center",
|
|
6
|
+
// The board exists before the first tool call, so a resumed connection has
|
|
7
|
+
// something to project rather than an empty state object.
|
|
19
8
|
// One projection replaces eleven `ctx.send("incidents", ...)` calls, and
|
|
20
9
|
// is the single place that decides caller PII stays server-side.
|
|
21
10
|
syncState: dispatchSlot.projection(dashboardView),
|
|
@@ -23,26 +12,10 @@ export default agent({
|
|
|
23
12
|
// one message ("unit twelve … respond to"). The default pipeline's
|
|
24
13
|
// `max_turn_silence` already tolerates that; reach for
|
|
25
14
|
// `assemblyAIStt({ maxTurnSilenceMs })` only if your callers pause longer.
|
|
26
|
-
systemPrompt,
|
|
27
15
|
greeting:
|
|
28
16
|
"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.",
|
|
29
17
|
|
|
30
18
|
// The system prompt instructs the model to use web_search and run_code, so
|
|
31
19
|
// they must be enabled here — the default builtin set does not include them.
|
|
32
20
|
builtinTools: ["think", "remember", "recall", "calculate", "web_search", "run_code"],
|
|
33
|
-
|
|
34
|
-
tools: {
|
|
35
|
-
incident_add_note: incidentAddNote,
|
|
36
|
-
incident_create: incidentCreate,
|
|
37
|
-
incident_escalate: incidentEscalate,
|
|
38
|
-
incident_get: incidentGet,
|
|
39
|
-
incident_triage: incidentTriage,
|
|
40
|
-
incident_update_status: incidentUpdateStatus,
|
|
41
|
-
ops_dashboard: opsDashboard,
|
|
42
|
-
ops_protocols: opsProtocols,
|
|
43
|
-
ops_run_scenario: opsRunScenario,
|
|
44
|
-
resources_dispatch: resourcesDispatch,
|
|
45
|
-
resources_get_available: resourcesGetAvailable,
|
|
46
|
-
resources_update_status: resourcesUpdateStatus,
|
|
47
|
-
},
|
|
48
21
|
});
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import "@alexkroman1/aai-ui/styles.css";
|
|
2
|
-
import type { ChatMessage } from "@alexkroman1/aai-ui";
|
|
3
|
-
import {
|
|
2
|
+
import type { AgentState, ChatMessage } from "@alexkroman1/aai-ui";
|
|
3
|
+
import {
|
|
4
|
+
AutoScroll,
|
|
5
|
+
client,
|
|
6
|
+
useAgentState,
|
|
7
|
+
useSession,
|
|
8
|
+
useUserTranscript,
|
|
9
|
+
} from "@alexkroman1/aai-ui";
|
|
4
10
|
import type { DashboardView, DispatchState, IncidentSummary, Severity, Status } from "./shared.ts";
|
|
5
11
|
import { dashboardView, dispatchSlot } from "./shared.ts";
|
|
6
12
|
|
|
@@ -55,17 +61,24 @@ const statusColors: Record<string, string> = {
|
|
|
55
61
|
// new DashboardView field can't silently miss the pre-first-tool-call render.
|
|
56
62
|
const EMPTY_DASH: DashboardView = dispatchSlot.projection(dashboardView)(undefined);
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
// The dot's colour per session state, as an EXHAUSTIVE map rather than an
|
|
65
|
+
// if-chain with a grey default.
|
|
66
|
+
//
|
|
67
|
+
// The palette is this template's own — every client here paints the same six
|
|
68
|
+
// states in its own colours, so the SDK has nothing to share but the union. What
|
|
69
|
+
// the SDK does own is `AgentState`, and `satisfies Record<AgentState, string>`
|
|
70
|
+
// is what borrows it: a state added there stops compiling here, where the
|
|
71
|
+
// `state === "…"` chain this replaced answered a new state with a silent grey
|
|
72
|
+
// badge in three separate files and no way to notice.
|
|
73
|
+
const STATE_COLORS = {
|
|
74
|
+
disconnected: "#6b7280",
|
|
75
|
+
connecting: "#6b7280",
|
|
76
|
+
ready: "#22c55e",
|
|
77
|
+
listening: "#22c55e",
|
|
78
|
+
thinking: "#eab308",
|
|
79
|
+
speaking: "#3b82f6",
|
|
80
|
+
error: "#6b7280",
|
|
81
|
+
} satisfies Record<AgentState, string>;
|
|
69
82
|
|
|
70
83
|
function Panel({ title, children }: { title: string; children: React.ReactNode }) {
|
|
71
84
|
return (
|
|
@@ -132,6 +145,10 @@ function IncidentCard({ inc }: { inc: IncidentSummary }) {
|
|
|
132
145
|
|
|
133
146
|
function App() {
|
|
134
147
|
const session = useSession();
|
|
148
|
+
// `speaking` and `text` in place of a `userTranscript !== null` check: `null`
|
|
149
|
+
// is silence and `""` is speech detected with no words back yet, and reading
|
|
150
|
+
// them as one falsy value hides the indicator at the start of every turn.
|
|
151
|
+
const { speaking, text: userTranscript } = useUserTranscript();
|
|
135
152
|
// The agent's own board, projected by `syncState`. This replaced a
|
|
136
153
|
// useState mirror that merged incident deltas out of tool events — the
|
|
137
154
|
// projection is already the complete list, so there is nothing to merge.
|
|
@@ -169,7 +186,7 @@ function App() {
|
|
|
169
186
|
<span
|
|
170
187
|
className="w-2.5 h-2.5 rounded-full inline-block"
|
|
171
188
|
style={{
|
|
172
|
-
background:
|
|
189
|
+
background: STATE_COLORS[session.state],
|
|
173
190
|
animation:
|
|
174
191
|
session.state === "listening"
|
|
175
192
|
? "dc-pulse 1.5s ease-in-out infinite"
|
|
@@ -249,7 +266,7 @@ function App() {
|
|
|
249
266
|
))}
|
|
250
267
|
</AutoScroll>
|
|
251
268
|
|
|
252
|
-
{
|
|
269
|
+
{speaking && (
|
|
253
270
|
<div
|
|
254
271
|
className="flex items-center px-4 py-2 text-xs italic min-h-8"
|
|
255
272
|
style={{ background: "#111827", borderTop: "1px solid #1e293b", color: "#64748b" }}
|
|
@@ -258,7 +275,7 @@ function App() {
|
|
|
258
275
|
className="w-2.5 h-2.5 rounded-full inline-block mr-2"
|
|
259
276
|
style={{ background: "#22c55e", animation: "dc-pulse 1.5s ease-in-out infinite" }}
|
|
260
277
|
/>
|
|
261
|
-
{
|
|
278
|
+
{userTranscript}
|
|
262
279
|
</div>
|
|
263
280
|
)}
|
|
264
281
|
{session.error && (
|