@alexkroman1/aai-cli 5.14.0 → 6.2.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 +14 -10
- package/dist/build-DQJ1ZSm9.mjs +0 -39
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as errorCode } from "./_utils-B8QmtFhK.mjs";
|
|
3
|
+
import { n as withPreservedNodeEnv } from "./_vite-env-BNveawd1.mjs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import { build } from "vite";
|
|
7
|
+
import { BaseBuilder, applySwcTransform, detectWorkflowPatterns, shouldTransformFile } from "@workflow/builders";
|
|
8
|
+
//#region workflow-bundler.ts
|
|
9
|
+
/**
|
|
10
|
+
* Workflow bundling — turning a project's `workflows/` directory into the two
|
|
11
|
+
* small artifacts a guest needs to run durable workflows.
|
|
12
|
+
*
|
|
13
|
+
* Public (no `_` prefix) for the same reason as `worker-bundler.ts`: the studio
|
|
14
|
+
* builds its workspaces through this too, so a workflow published from the
|
|
15
|
+
* browser comes out of the same pass as one from `aai build`.
|
|
16
|
+
*
|
|
17
|
+
* @internal — build hook for aai-server/the studio; not a supported public API
|
|
18
|
+
* and not covered by semver.
|
|
19
|
+
*
|
|
20
|
+
* ## Why this exists at all
|
|
21
|
+
*
|
|
22
|
+
* The Workflow Development Kit's own integrations (Next, Nitro, SvelteKit) build
|
|
23
|
+
* workflow routes while building the SERVER, by scanning `workflows/` and
|
|
24
|
+
* emitting handler files. That model does not fit this platform: the guest image
|
|
25
|
+
* is baked once and then serves MANY tenants' agents, each arriving over
|
|
26
|
+
* `bundle/load` at runtime. There is no `workflows/` directory in existence when
|
|
27
|
+
* the harness is built. So the transform has to happen per tenant at deploy
|
|
28
|
+
* time — here — and the guest receives the result as data.
|
|
29
|
+
*
|
|
30
|
+
* ## The two artifacts, and why they are small
|
|
31
|
+
*
|
|
32
|
+
* A default `workflow build` emits a 3.7 MB flow bundle and a 12 MB step bundle,
|
|
33
|
+
* because each one inlines the whole WDK runtime. Neither could ride the guest's
|
|
34
|
+
* single-ESM-string delivery. Two settings fix that, and both are load-bearing:
|
|
35
|
+
*
|
|
36
|
+
* - **`externalPackages: ["workflow", …]`** — the WDK is resolved from the
|
|
37
|
+
* guest's BAKED image instead of being inlined. Step bundle: 12 MB → ~7 KB.
|
|
38
|
+
* - **`bundleFinalOutput: false`** — skips wrapping the workflow-mode code in a
|
|
39
|
+
* runtime host, which is exactly what `workflowEntrypoint(code)` supplies
|
|
40
|
+
* itself at the other end. Flow bundle: 3.7 MB → ~69 KB.
|
|
41
|
+
*
|
|
42
|
+
* So `workflowCode` is passed to `workflowEntrypoint()` in the guest and
|
|
43
|
+
* `stepCode` is evaluated there to register its step functions.
|
|
44
|
+
*
|
|
45
|
+
* ## The THIRD transform, which is the agent bundle's
|
|
46
|
+
*
|
|
47
|
+
* Those two are what the queue runs. The agent bundle needs a third —
|
|
48
|
+
* `applySwcTransform(…, "client")`, wired in as {@link workflowClientPlugin} —
|
|
49
|
+
* and without it the whole mechanism is inert: `ctx.workflows.start` reads the
|
|
50
|
+
* `workflowId` the compiler attaches to a directive body, and Vite bundling
|
|
51
|
+
* `workflows/research.ts` the ordinary way attaches nothing. The symptom is
|
|
52
|
+
* `MISSING_WORKFLOW_ID_MESSAGE` at the first `start()` — an agent that builds,
|
|
53
|
+
* deploys, boots and answers the phone, and cannot start a run.
|
|
54
|
+
*
|
|
55
|
+
* The plugin transforms EXACTLY the files the builder scanned (`inputFiles`),
|
|
56
|
+
* not "every file with a directive". Same list, same `moduleSpecifierRoot`,
|
|
57
|
+
* therefore the same ids by construction — a body outside `workflows/` cannot
|
|
58
|
+
* acquire an id that no flow bundle registered, which would trade a clear
|
|
59
|
+
* failure at `start()` for a run that enqueues and then fails at replay.
|
|
60
|
+
*
|
|
61
|
+
* ## Config details that are not optional
|
|
62
|
+
*
|
|
63
|
+
* Each of these cost real time to find, and none fails in a way that names
|
|
64
|
+
* itself:
|
|
65
|
+
*
|
|
66
|
+
* - `dirs` must carry the `./` prefix. A bare `"workflows"` crashes inside
|
|
67
|
+
* enhanced-resolve with `Cannot read properties of undefined (reading
|
|
68
|
+
* 'length')` from `join(undefined, …)`, nowhere near the cause.
|
|
69
|
+
* - Every bundle path must be ABSOLUTE, for the same reason.
|
|
70
|
+
* - `projectRoot` and `moduleSpecifierRoot` must be set explicitly; they do not
|
|
71
|
+
* default to `workingDir` on the path this takes.
|
|
72
|
+
* - `keepInterimBundleContext` must stay off — it leaves an esbuild watch context
|
|
73
|
+
* alive, so a one-shot build never exits.
|
|
74
|
+
*/
|
|
75
|
+
/**
|
|
76
|
+
* The directory a project's `"use workflow"` bodies live in.
|
|
77
|
+
*
|
|
78
|
+
* The WDK builder's convention, not ours, and it is why a workflow body cannot
|
|
79
|
+
* live in `agent.ts`: only files under here are transformed. A body outside it
|
|
80
|
+
* runs inline, once, with no durability and nothing reporting that.
|
|
81
|
+
*/
|
|
82
|
+
const WORKFLOWS_DIR = "workflows";
|
|
83
|
+
/**
|
|
84
|
+
* Packages left OUT of both bundles, resolved from the guest's baked image.
|
|
85
|
+
*
|
|
86
|
+
* `workflow` alone would nearly do it — its subpaths are what user code imports —
|
|
87
|
+
* but the `@workflow/*` internals are what the transform's own emitted imports
|
|
88
|
+
* reach for, and inlining those is most of the 12 MB.
|
|
89
|
+
*/
|
|
90
|
+
const WDK_EXTERNAL = [
|
|
91
|
+
"workflow",
|
|
92
|
+
"@workflow/core",
|
|
93
|
+
"@workflow/errors",
|
|
94
|
+
"@workflow/utils",
|
|
95
|
+
"@workflow/world"
|
|
96
|
+
];
|
|
97
|
+
/** Scratch directory for the builder's file output, under the CLI's own dot-dir. */
|
|
98
|
+
const SCRATCH_REL = path.join(".aai", "workflow-build");
|
|
99
|
+
/**
|
|
100
|
+
* What makes a CJS dependency survive into the ESM step bundle.
|
|
101
|
+
*
|
|
102
|
+
* esbuild cannot statically rewrite `require("node:assert")` inside a bundled
|
|
103
|
+
* CommonJS module, so it emits a `__require` shim — and that shim's fallback
|
|
104
|
+
* THROWS: `Dynamic require of "node:assert" is not supported`. A step bundles
|
|
105
|
+
* everything it imports and npm is full of CJS, so any step reaching a package
|
|
106
|
+
* with a CJS dependency anywhere in its graph failed AT MODULE LOAD, before a
|
|
107
|
+
* single line of the step ran.
|
|
108
|
+
*
|
|
109
|
+
* That is not a hypothetical, and the way it presents is the argument for
|
|
110
|
+
* fixing it here. `research-workflow` imports `webSearch` from
|
|
111
|
+
* `@alexkroman1/aai/tools`, which reaches `host/ssrf.ts`, which imports
|
|
112
|
+
* **undici** — 118 dynamic requires, all of them `node:` builtins. `aai dev`
|
|
113
|
+
* then never listened at all: the message named a Node builtin the author
|
|
114
|
+
* never mentions, nothing named the package or the import that pulled it, and
|
|
115
|
+
* because the step bundle is loaded before the server binds there was no
|
|
116
|
+
* server to ask. It also does not reproduce in-tree, where `@dev/source`
|
|
117
|
+
* resolves the SDK to TypeScript — only against the published `dist` — so
|
|
118
|
+
* every gate short of the e2e suite was green.
|
|
119
|
+
*
|
|
120
|
+
* The shim itself is the fix's whole mechanism: esbuild writes
|
|
121
|
+
* `typeof require !== "undefined" ? require : <thrower>`, so a real `require`
|
|
122
|
+
* in scope is USED. This defines one from `import.meta.url` and is prepended,
|
|
123
|
+
* which puts it ahead of the `var __require = …` initializer that reads it.
|
|
124
|
+
* The flow bundle deliberately gets none — it is compiled in a `node:vm`
|
|
125
|
+
* Script, where `import.meta` does not exist.
|
|
126
|
+
*/
|
|
127
|
+
const STEP_REQUIRE_SHIM = [
|
|
128
|
+
"import { createRequire as __aaiCreateRequire } from \"node:module\";",
|
|
129
|
+
"const require = __aaiCreateRequire(import.meta.url);",
|
|
130
|
+
""
|
|
131
|
+
].join("\n");
|
|
132
|
+
/**
|
|
133
|
+
* The builder, with the config gotchas above applied once.
|
|
134
|
+
*
|
|
135
|
+
* `BaseBuilder` is abstract over `build()`, so a subclass is the supported way to
|
|
136
|
+
* choose which bundles to emit and how — the WDK's own framework integrations do
|
|
137
|
+
* the same.
|
|
138
|
+
*/
|
|
139
|
+
var AaiWorkflowBuilder = class extends BaseBuilder {
|
|
140
|
+
/**
|
|
141
|
+
* Where `build()` leaves its result.
|
|
142
|
+
*
|
|
143
|
+
* `BaseBuilder.build()` is typed `Promise<void>`, so a subclass cannot return
|
|
144
|
+
* the artifacts from it — and parameter properties are unavailable under this
|
|
145
|
+
* repo's `erasableSyntaxOnly`, so the fields are declared the long way too.
|
|
146
|
+
*/
|
|
147
|
+
output;
|
|
148
|
+
outDir;
|
|
149
|
+
constructor(cwd, outDir) {
|
|
150
|
+
super({
|
|
151
|
+
buildTarget: "standalone",
|
|
152
|
+
dirs: [`./${WORKFLOWS_DIR}`],
|
|
153
|
+
workingDir: cwd,
|
|
154
|
+
projectRoot: cwd,
|
|
155
|
+
moduleSpecifierRoot: cwd,
|
|
156
|
+
externalPackages: [...WDK_EXTERNAL],
|
|
157
|
+
stepsBundlePath: path.join(outDir, "step.mjs"),
|
|
158
|
+
workflowsBundlePath: path.join(outDir, "flow.mjs"),
|
|
159
|
+
webhookBundlePath: path.join(outDir, "webhook.mjs"),
|
|
160
|
+
suppressCreateWorkflowsBundleLogs: true,
|
|
161
|
+
suppressCreateWebhookBundleLogs: true,
|
|
162
|
+
suppressCreateManifestLogs: true
|
|
163
|
+
});
|
|
164
|
+
this.outDir = outDir;
|
|
165
|
+
}
|
|
166
|
+
async build() {
|
|
167
|
+
const inputFiles = await this.getInputFiles();
|
|
168
|
+
const flowFile = path.join(this.outDir, "flow.mjs");
|
|
169
|
+
const stepFile = path.join(this.outDir, "step.mjs");
|
|
170
|
+
const { manifest } = await this.createWorkflowsBundle({
|
|
171
|
+
inputFiles,
|
|
172
|
+
format: "esm",
|
|
173
|
+
outfile: flowFile,
|
|
174
|
+
bundleFinalOutput: false
|
|
175
|
+
});
|
|
176
|
+
await this.createStepsBundle({
|
|
177
|
+
inputFiles,
|
|
178
|
+
format: "esm",
|
|
179
|
+
outfile: stepFile
|
|
180
|
+
});
|
|
181
|
+
const [workflowCode, stepCode] = await Promise.all([fs.readFile(flowFile, "utf-8"), fs.readFile(stepFile, "utf-8")]);
|
|
182
|
+
this.output = {
|
|
183
|
+
workflowCode,
|
|
184
|
+
stepCode: STEP_REQUIRE_SHIM + stepCode,
|
|
185
|
+
manifest,
|
|
186
|
+
inputFiles
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Attach the compiler's `workflowId`/`stepId` to the agent bundle's copy of
|
|
192
|
+
* each directive body — the third transform, see the module doc.
|
|
193
|
+
*
|
|
194
|
+
* `enforce: "pre"` so it sees the file before Vite's own TypeScript pass: the
|
|
195
|
+
* swc transform reads types itself (it is given the filename to infer syntax),
|
|
196
|
+
* and its output is plain JS that the later pass leaves alone.
|
|
197
|
+
*
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
function workflowClientPlugin(cwd, inputFiles) {
|
|
201
|
+
const scanned = new Set(inputFiles.map((file) => path.resolve(cwd, file)));
|
|
202
|
+
return {
|
|
203
|
+
name: "aai:workflow-client",
|
|
204
|
+
enforce: "pre",
|
|
205
|
+
async transform(code, id) {
|
|
206
|
+
const file = path.resolve(id.split("?")[0] ?? id);
|
|
207
|
+
if (!scanned.has(file)) return;
|
|
208
|
+
if (!shouldTransformFile(file, detectWorkflowPatterns(code))) return;
|
|
209
|
+
const { code: transformed } = await applySwcTransform(path.relative(cwd, file), code, "client", file, cwd, cwd);
|
|
210
|
+
return {
|
|
211
|
+
code: transformed,
|
|
212
|
+
map: null
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Build a project's workflows, or resolve `undefined` when it declares none.
|
|
219
|
+
*
|
|
220
|
+
* `undefined` rather than empty strings, because "this project has no workflows"
|
|
221
|
+
* is the common case — every voice agent that never reaches for one — and the
|
|
222
|
+
* guest must be able to tell it apart from "the build produced nothing", which
|
|
223
|
+
* would be a bug.
|
|
224
|
+
*
|
|
225
|
+
* @internal
|
|
226
|
+
*/
|
|
227
|
+
async function buildWorkflows(cwd) {
|
|
228
|
+
if (!await hasWorkflowsDir(cwd)) return;
|
|
229
|
+
const outDir = path.join(cwd, SCRATCH_REL);
|
|
230
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
231
|
+
try {
|
|
232
|
+
const builder = new AaiWorkflowBuilder(cwd, outDir);
|
|
233
|
+
await builder.build();
|
|
234
|
+
const built = builder.output;
|
|
235
|
+
if (!built) return;
|
|
236
|
+
return built.workflowCode.trim() === "" ? void 0 : built;
|
|
237
|
+
} finally {
|
|
238
|
+
await fs.rm(outDir, {
|
|
239
|
+
recursive: true,
|
|
240
|
+
force: true
|
|
241
|
+
}).catch(() => void 0);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Does this project have a `workflows/` directory with anything in it? */
|
|
245
|
+
async function hasWorkflowsDir(cwd) {
|
|
246
|
+
try {
|
|
247
|
+
return (await fs.readdir(path.join(cwd, WORKFLOWS_DIR))).some((name) => /\.(ts|tsx|js|jsx|mjs)$/.test(name));
|
|
248
|
+
} catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region worker-bundler.ts
|
|
254
|
+
/**
|
|
255
|
+
* Generated wrapper entry, written under `.aai/` for the duration of the
|
|
256
|
+
* build (the CLI's own scratch dir — dot-paths are ignored by the dev
|
|
257
|
+
* watcher, and the studio's workspace materialization never writes there).
|
|
258
|
+
*/
|
|
259
|
+
const WRAPPER_ENTRY_REL = path.join(".aai", "worker-entry.ts");
|
|
260
|
+
/** Extensions a tool module may be authored in (mirrors the SDK's registry). */
|
|
261
|
+
const TOOL_MODULE_EXT_RE = /\.(?:m?ts|tsx)$/;
|
|
262
|
+
/** A co-located spec is not a tool. */
|
|
263
|
+
const TOOL_SPEC_RE = /\.(?:test|spec)\.[^.]+$/;
|
|
264
|
+
/**
|
|
265
|
+
* The project's `tools/` directory, as file names relative to it.
|
|
266
|
+
*
|
|
267
|
+
* **This is the whole of "discovery", and it happens HERE because the guest has
|
|
268
|
+
* no filesystem.** A sandbox is handed one ESM string, so the only place a
|
|
269
|
+
* directory can be turned into modules is where the bundle is assembled — the
|
|
270
|
+
* same lowering eve does (`readdir` → static import list, which the bundler then
|
|
271
|
+
* follows). The names are validated by `toolRegistry` at bundle-evaluation time
|
|
272
|
+
* rather than here, so one implementation owns the rules.
|
|
273
|
+
*
|
|
274
|
+
* Sorted, so the emitted entry is byte-stable for a given directory: an entry
|
|
275
|
+
* that reordered per readdir would change the bundle hash for no reason.
|
|
276
|
+
*/
|
|
277
|
+
async function discoverToolFiles(cwd) {
|
|
278
|
+
const root = path.join(cwd, "tools");
|
|
279
|
+
let entries;
|
|
280
|
+
try {
|
|
281
|
+
entries = await fs.readdir(root, {
|
|
282
|
+
withFileTypes: true,
|
|
283
|
+
recursive: true
|
|
284
|
+
});
|
|
285
|
+
} catch (err) {
|
|
286
|
+
if (errorCode(err) === "ENOENT") return [];
|
|
287
|
+
throw err;
|
|
288
|
+
}
|
|
289
|
+
return entries.filter((e) => e.isFile() && TOOL_MODULE_EXT_RE.test(e.name) && !TOOL_SPEC_RE.test(e.name)).map((e) => path.relative(root, path.join(e.parentPath, e.name)).split(path.sep).join("/")).sort();
|
|
290
|
+
}
|
|
291
|
+
/** The prose slot: one file, beside `agent.ts`, named by convention. */
|
|
292
|
+
const SYSTEM_PROMPT_FILE = "system-prompt.md";
|
|
293
|
+
/**
|
|
294
|
+
* Whether the project keeps its system prompt in a file.
|
|
295
|
+
*
|
|
296
|
+
* The other half of "a file beside `agent.ts` can BE the thing", and it happens
|
|
297
|
+
* here for the same reason `discoverToolFiles` does — the guest has no
|
|
298
|
+
* filesystem, so the read belongs where the bundle is assembled. What the file
|
|
299
|
+
* MEANS is `withSystemPrompt`'s to decide (the author may have imported and
|
|
300
|
+
* composed it, in which case discovery must not apply it twice); this only
|
|
301
|
+
* answers whether there is one.
|
|
302
|
+
*/
|
|
303
|
+
async function hasSystemPromptFile(cwd) {
|
|
304
|
+
const nested = path.join(cwd, "system-prompt");
|
|
305
|
+
if ((await fs.stat(nested).catch(() => void 0))?.isDirectory() === true) throw new Error(`${nested} is a directory. A system prompt is ONE file — rename it to ${SYSTEM_PROMPT_FILE}, or import the pieces yourself and compose them into \`systemPrompt\`. There is deliberately no concatenation order for a directory.`);
|
|
306
|
+
try {
|
|
307
|
+
return (await fs.stat(path.join(cwd, SYSTEM_PROMPT_FILE))).isFile();
|
|
308
|
+
} catch (err) {
|
|
309
|
+
if (errorCode(err) === "ENOENT") return false;
|
|
310
|
+
throw err;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function wrapperEntrySource(runtime, workflows, toolFiles, systemPromptFile) {
|
|
314
|
+
const toolImports = toolFiles.map((file, i) => `import * as __aaiTool${i} from "../tools/${file}";`).join("\n");
|
|
315
|
+
const toolEntries = toolFiles.map((file, i) => ` ${JSON.stringify(`tools/${file}`)}: __aaiTool${i},`).join("\n");
|
|
316
|
+
return `import def from "../agent.ts";
|
|
317
|
+
import { agentToolsToSchemas, toAgentConfig, toolRegistry, withSystemPrompt, withTools } from "@alexkroman1/aai/manifest";
|
|
318
|
+
${runtime ? `import { createRuntime } from "@alexkroman1/aai/runtime";` : ""}
|
|
319
|
+
${systemPromptFile ? `import __aaiSystemPrompt from "../${SYSTEM_PROMPT_FILE}?raw";` : ""}
|
|
320
|
+
${toolImports}
|
|
321
|
+
// A tool's name is its file name. The map is built here rather than written in
|
|
322
|
+
// agent.ts, so a file that exists is a tool the model can call — there is no
|
|
323
|
+
// registration step to forget.
|
|
324
|
+
//
|
|
325
|
+
// \`system-prompt.md\` arrives the same way, and the \`?raw\` lives HERE rather
|
|
326
|
+
// than in the author's own \`agent.ts\`: it is a Vite convention, and the whole
|
|
327
|
+
// point of generating this entry is that a bundler feature never has to appear
|
|
328
|
+
// in user-authored space.
|
|
329
|
+
const __aaiAgent = ${systemPromptFile ? "withSystemPrompt(" : ""}withTools(
|
|
330
|
+
def,
|
|
331
|
+
toolRegistry({
|
|
332
|
+
${toolEntries}
|
|
333
|
+
}),
|
|
334
|
+
)${systemPromptFile ? ", __aaiSystemPrompt)" : ""};
|
|
335
|
+
export default __aaiAgent;
|
|
336
|
+
export const __aaiConfig = {
|
|
337
|
+
...toAgentConfig(__aaiAgent),
|
|
338
|
+
toolSchemas: agentToolsToSchemas(__aaiAgent.tools ?? {}),
|
|
339
|
+
};
|
|
340
|
+
${runtime ? `export const __aaiCreateRuntime = (opts: Record<string, unknown>) =>
|
|
341
|
+
createRuntime({ ...opts, agent: __aaiAgent });
|
|
342
|
+
` : ""}${workflows ? `// The compiled workflow surface, carried as DATA. \`__aaiWorkflowCode\` goes to
|
|
343
|
+
// \`workflowEntrypoint(code)\` and \`__aaiStepCode\` is evaluated by the guest so its
|
|
344
|
+
// \`registerStepFunction\` calls run. Strings rather than modules because the guest
|
|
345
|
+
// receives exactly one ESM string and never sees this project's filesystem.
|
|
346
|
+
export const __aaiWorkflowCode = ${JSON.stringify(workflows.workflowCode)};
|
|
347
|
+
export const __aaiStepCode = ${JSON.stringify(workflows.stepCode)};
|
|
348
|
+
` : ""}`;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Bundle agent.ts into a single ESM string for the sandbox worker.
|
|
352
|
+
*
|
|
353
|
+
* Zod is bundled in — zod 4's `Function()` usage is wrapped in try/catch
|
|
354
|
+
* and gracefully degrades in restricted environments like Deno.
|
|
355
|
+
*
|
|
356
|
+
* @internal — build hook for aai-server/the studio; not a supported public
|
|
357
|
+
* API and not covered by semver.
|
|
358
|
+
*/
|
|
359
|
+
async function buildWorker(cwd, opts = {}) {
|
|
360
|
+
const wrapperPath = path.join(cwd, WRAPPER_ENTRY_REL);
|
|
361
|
+
await fs.mkdir(path.dirname(wrapperPath), { recursive: true });
|
|
362
|
+
await fs.writeFile(wrapperPath, wrapperEntrySource(opts.runtime !== false, opts.workflows, await discoverToolFiles(cwd), await hasSystemPromptFile(cwd)), "utf-8");
|
|
363
|
+
const plugins = [...opts.plugins ?? [], ...opts.workflows ? [workflowClientPlugin(cwd, opts.workflows.inputFiles)] : []];
|
|
364
|
+
let result;
|
|
365
|
+
try {
|
|
366
|
+
result = await withPreservedNodeEnv(() => build({
|
|
367
|
+
root: cwd,
|
|
368
|
+
logLevel: "silent",
|
|
369
|
+
...opts.configFile === false && { configFile: false },
|
|
370
|
+
...plugins.length > 0 && { plugins },
|
|
371
|
+
ssr: { noExternal: true },
|
|
372
|
+
build: {
|
|
373
|
+
ssr: true,
|
|
374
|
+
lib: {
|
|
375
|
+
entry: wrapperPath,
|
|
376
|
+
formats: ["es"],
|
|
377
|
+
fileName: "worker"
|
|
378
|
+
},
|
|
379
|
+
target: "node20",
|
|
380
|
+
minify: opts.minify ? "oxc" : false,
|
|
381
|
+
write: false,
|
|
382
|
+
rollupOptions: { output: {
|
|
383
|
+
entryFileNames: "[name].js",
|
|
384
|
+
codeSplitting: false
|
|
385
|
+
} }
|
|
386
|
+
}
|
|
387
|
+
}));
|
|
388
|
+
} finally {
|
|
389
|
+
await fs.rm(wrapperPath, { force: true }).catch(() => void 0);
|
|
390
|
+
}
|
|
391
|
+
const output = Array.isArray(result) ? result[0] : result;
|
|
392
|
+
if (!output) throw new Error("Vite produced no output for agent.ts");
|
|
393
|
+
const chunk = output.output.find((o) => o.type === "chunk" && o.isEntry);
|
|
394
|
+
if (!chunk) throw new Error("Vite produced no entry chunk for agent.ts");
|
|
395
|
+
return chunk.code;
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
398
|
+
export { buildWorkflows as n, buildWorker as t };
|
package/dist/worker-bundler.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PluginOption } from "vite";
|
|
2
|
+
import { type WorkflowBundleOutput } from "./workflow-bundler.ts";
|
|
2
3
|
/**
|
|
3
4
|
* Options for worker bundling.
|
|
4
5
|
*
|
|
@@ -24,6 +25,19 @@ export type BuildWorkerOptions = {
|
|
|
24
25
|
* rebuild would turn the watch loop from sub-second into multi-second.
|
|
25
26
|
*/
|
|
26
27
|
runtime?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The project's compiled workflows, when it declares any.
|
|
30
|
+
*
|
|
31
|
+
* Embedded in the worker as two string exports rather than shipped as extra
|
|
32
|
+
* files, because the guest's `bundle/load` contract is ONE ESM string. See
|
|
33
|
+
* `wrapperEntrySource`.
|
|
34
|
+
*
|
|
35
|
+
* It also switches on the client transform (`workflowClientPlugin`), which is
|
|
36
|
+
* what puts a `workflowId` on the agent's own copy of each body. Passing the
|
|
37
|
+
* strings without it produces a bundle that serves every workflow route and
|
|
38
|
+
* cannot start a run.
|
|
39
|
+
*/
|
|
40
|
+
workflows?: WorkflowBundleOutput | undefined;
|
|
27
41
|
};
|
|
28
42
|
/**
|
|
29
43
|
* Bundle agent.ts into a single ESM string for the sandbox worker.
|
package/dist/worker-bundler.mjs
CHANGED
|
@@ -1,110 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
|
-
import { build } from "vite";
|
|
6
|
-
//#region worker-bundler.ts
|
|
7
|
-
/**
|
|
8
|
-
* Worker bundling — the one implementation of "turn an `agent.ts` into the
|
|
9
|
-
* ESM the guest sandbox loads".
|
|
10
|
-
*
|
|
11
|
-
* Public (no `_` prefix) for the same reason as `client-bundler.ts`: the
|
|
12
|
-
* platform's browser studio builds its workspaces through this function, so a
|
|
13
|
-
* worker published from the browser comes out of the same Vite/Rollup pass as
|
|
14
|
-
* one from `aai deploy`.
|
|
15
|
-
*
|
|
16
|
-
* @internal — build hook for aai-server/the studio; not a supported public
|
|
17
|
-
* API and not covered by semver. The lack of a `_` prefix is packaging (the
|
|
18
|
-
* subpath must be importable cross-package), not an invitation: user code
|
|
19
|
-
* should never import from `@alexkroman1/aai-cli`.
|
|
20
|
-
*
|
|
21
|
-
* Every worker is built through a generated wrapper entry that re-exports the
|
|
22
|
-
* agent *and* its extracted config as `__aaiConfig` (via the dependency-free
|
|
23
|
-
* `@alexkroman1/aai/manifest` helpers, bundled in). The guest harness returns
|
|
24
|
-
* that export from `bundle/load`, which is how the platform obtains an
|
|
25
|
-
* agent's config without ever evaluating tenant code on the host — the
|
|
26
|
-
* `POST /deploy` route and the studio's sandbox inspection both rely on it.
|
|
27
|
-
*
|
|
28
|
-
* **The worker ships its own runtime.** Deploy builds also export
|
|
29
|
-
* `__aaiCreateRuntime` — a factory over the *user's installed* SDK's
|
|
30
|
-
* `createRuntime`, bundled in alongside the provider SDKs. The guest harness
|
|
31
|
-
* builds the session runtime through it, so a deployed agent runs exactly the
|
|
32
|
-
* runtime version it was built and tested against (identical to `aai dev`),
|
|
33
|
-
* instead of whatever SDK the platform's harness image was baked with. The
|
|
34
|
-
* harness↔bundle contract is deliberately tiny: the factory takes
|
|
35
|
-
* `{ env, db?, runCode? }` and returns `{ startSession, shutdown }`.
|
|
36
|
-
*
|
|
37
|
-
* What the studio supplies via options, because a workspace is not a project:
|
|
38
|
-
*
|
|
39
|
-
* - **`configFile: false`.** Workspace files are untrusted and a Vite config
|
|
40
|
-
* is executable host code.
|
|
41
|
-
* - **`plugins`.** The studio adds its import allowlist; without it, Vite
|
|
42
|
-
* would happily resolve any package in the server's `node_modules`.
|
|
43
|
-
*/
|
|
44
|
-
/**
|
|
45
|
-
* Generated wrapper entry, written under `.aai/` for the duration of the
|
|
46
|
-
* build (the CLI's own scratch dir — dot-paths are ignored by the dev
|
|
47
|
-
* watcher, and the studio's workspace materialization never writes there).
|
|
48
|
-
*/
|
|
49
|
-
const WRAPPER_ENTRY_REL = path.join(".aai", "worker-entry.ts");
|
|
50
|
-
function wrapperEntrySource(runtime) {
|
|
51
|
-
return `import def from "../agent.ts";
|
|
52
|
-
import { agentToolsToSchemas, toAgentConfig } from "@alexkroman1/aai/manifest";
|
|
53
|
-
${runtime ? `import { createRuntime } from "@alexkroman1/aai/runtime";` : ""}
|
|
54
|
-
export default def;
|
|
55
|
-
export const __aaiConfig = {
|
|
56
|
-
...toAgentConfig(def),
|
|
57
|
-
toolSchemas: agentToolsToSchemas(def.tools ?? {}),
|
|
58
|
-
};
|
|
59
|
-
${runtime ? `export const __aaiCreateRuntime = (opts: Record<string, unknown>) =>
|
|
60
|
-
createRuntime({ ...opts, agent: def });
|
|
61
|
-
` : ""}`;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Bundle agent.ts into a single ESM string for the sandbox worker.
|
|
65
|
-
*
|
|
66
|
-
* Zod is bundled in — zod 4's `Function()` usage is wrapped in try/catch
|
|
67
|
-
* and gracefully degrades in restricted environments like Deno.
|
|
68
|
-
*
|
|
69
|
-
* @internal — build hook for aai-server/the studio; not a supported public
|
|
70
|
-
* API and not covered by semver.
|
|
71
|
-
*/
|
|
72
|
-
async function buildWorker(cwd, opts = {}) {
|
|
73
|
-
const wrapperPath = path.join(cwd, WRAPPER_ENTRY_REL);
|
|
74
|
-
await fs.mkdir(path.dirname(wrapperPath), { recursive: true });
|
|
75
|
-
await fs.writeFile(wrapperPath, wrapperEntrySource(opts.runtime !== false), "utf-8");
|
|
76
|
-
let result;
|
|
77
|
-
try {
|
|
78
|
-
result = await withPreservedNodeEnv(() => build({
|
|
79
|
-
root: cwd,
|
|
80
|
-
logLevel: "silent",
|
|
81
|
-
...opts.configFile === false && { configFile: false },
|
|
82
|
-
...opts.plugins && { plugins: opts.plugins },
|
|
83
|
-
ssr: { noExternal: true },
|
|
84
|
-
build: {
|
|
85
|
-
ssr: true,
|
|
86
|
-
lib: {
|
|
87
|
-
entry: wrapperPath,
|
|
88
|
-
formats: ["es"],
|
|
89
|
-
fileName: "worker"
|
|
90
|
-
},
|
|
91
|
-
target: "node20",
|
|
92
|
-
minify: opts.minify ? "oxc" : false,
|
|
93
|
-
write: false,
|
|
94
|
-
rollupOptions: { output: {
|
|
95
|
-
entryFileNames: "[name].js",
|
|
96
|
-
codeSplitting: false
|
|
97
|
-
} }
|
|
98
|
-
}
|
|
99
|
-
}));
|
|
100
|
-
} finally {
|
|
101
|
-
await fs.rm(wrapperPath, { force: true }).catch(() => void 0);
|
|
102
|
-
}
|
|
103
|
-
const output = Array.isArray(result) ? result[0] : result;
|
|
104
|
-
if (!output) throw new Error("Vite produced no output for agent.ts");
|
|
105
|
-
const chunk = output.output.find((o) => o.type === "chunk" && o.isEntry);
|
|
106
|
-
if (!chunk) throw new Error("Vite produced no entry chunk for agent.ts");
|
|
107
|
-
return chunk.code;
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
2
|
+
import { t as buildWorker } from "./worker-bundler-CIdDhZ0c.mjs";
|
|
110
3
|
export { buildWorker };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as ok, n as fail } from "./_output-CKkmWs7i.mjs";
|
|
3
|
+
import { n as log } from "./_ui-u7T4YooX.mjs";
|
|
4
|
+
import { n as getServerInfo } from "./_agent-vGW5SBnX.mjs";
|
|
5
|
+
import { errorMessage, omitUndefined } from "@alexkroman1/aai/utils";
|
|
6
|
+
import { createWorkflowApiClient } from "@alexkroman1/aai/workflow-api";
|
|
7
|
+
//#region workflow.ts
|
|
8
|
+
/** Runs listed when the caller names no limit — a terminal is not a dashboard. */
|
|
9
|
+
const DEFAULT_RUN_LIMIT = 20;
|
|
10
|
+
/**
|
|
11
|
+
* A client for the agent's workflow API, plus the bearer when one was given.
|
|
12
|
+
*
|
|
13
|
+
* `getServerInfo` is what turns "this directory" into an origin and a published
|
|
14
|
+
* slug, and it already refuses a project that has never been deployed with the
|
|
15
|
+
* sentence naming `aai publish`. The client is handed the AGENT's base URL and
|
|
16
|
+
* appends the route prefix itself, so the `/workflows` literal is not spelled
|
|
17
|
+
* here — it is the same constant the server matches on.
|
|
18
|
+
*
|
|
19
|
+
* `serverUrl` is joined as-is: `resolveServerUrl` is the single producer of
|
|
20
|
+
* every origin that reaches here and strips trailing slashes once, at
|
|
21
|
+
* resolution time, precisely so join sites do not each carry a copy. The copy
|
|
22
|
+
* this used to hold also DISAGREED with it — `/\/$/` takes one slash where the
|
|
23
|
+
* upstream `/\/+$/` takes all — so the two would have differed on the only
|
|
24
|
+
* input either was written for.
|
|
25
|
+
*/
|
|
26
|
+
async function target(cwd, opts) {
|
|
27
|
+
const { serverUrl, slug } = await getServerInfo(cwd, opts.server);
|
|
28
|
+
return {
|
|
29
|
+
api: createWorkflowApiClient({
|
|
30
|
+
baseUrl: `${serverUrl}/${slug}`,
|
|
31
|
+
...omitUndefined({ token: opts.token })
|
|
32
|
+
}),
|
|
33
|
+
slug
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Run one call, turning a rejection into a `CommandResult`.
|
|
38
|
+
*
|
|
39
|
+
* The client throws with the AGENT'S own sentence — an unknown workflow names
|
|
40
|
+
* the declared ones, a 503 says the sandbox is still booting — and that text is
|
|
41
|
+
* the whole diagnostic, so it is surfaced rather than replaced with a status
|
|
42
|
+
* code. `errorMessage` rather than `instanceof Error`, because a rejection that
|
|
43
|
+
* is message-bearing without being an `Error` would otherwise print as
|
|
44
|
+
* `[object Object]`.
|
|
45
|
+
*/
|
|
46
|
+
async function attempt(call) {
|
|
47
|
+
try {
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
value: await call()
|
|
51
|
+
};
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
error: errorMessage(err)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** `aai workflow list` — what this agent declares. */
|
|
60
|
+
async function executeWorkflowList(cwd, opts) {
|
|
61
|
+
const { api, slug } = await target(cwd, opts);
|
|
62
|
+
const res = await attempt(() => api.list());
|
|
63
|
+
if (!res.ok) return fail("workflow_list_failed", res.error, HINT_BROKER);
|
|
64
|
+
const workflows = res.value;
|
|
65
|
+
if (workflows.length === 0) log.info(`${slug} declares no workflows`);
|
|
66
|
+
else for (const w of workflows) log.info(`${w.name}${w.description ? ` — ${w.description}` : ""}`);
|
|
67
|
+
return ok({ workflows });
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* `aai workflow runs <name>` — recent runs, newest first.
|
|
71
|
+
*
|
|
72
|
+
* `recent` rather than `find`, so the query carries no `key`: a terminal has no
|
|
73
|
+
* correlation key to ask about, and most runs carry none.
|
|
74
|
+
*/
|
|
75
|
+
async function executeWorkflowRuns(cwd, workflow, opts) {
|
|
76
|
+
const { api } = await target(cwd, opts);
|
|
77
|
+
const res = await attempt(() => api.recent(workflow, { limit: opts.limit ?? DEFAULT_RUN_LIMIT }));
|
|
78
|
+
if (!res.ok) return fail("workflow_runs_failed", res.error, HINT_BROKER);
|
|
79
|
+
const runs = res.value;
|
|
80
|
+
if (runs.length === 0) log.info(`No runs of ${workflow} yet`);
|
|
81
|
+
for (const run of runs) log.info(formatRun(run));
|
|
82
|
+
return ok({ runs });
|
|
83
|
+
}
|
|
84
|
+
/** One run on one line — the id first, because it is what every other verb takes. */
|
|
85
|
+
function formatRun(run) {
|
|
86
|
+
const parts = [run.runId, run.status];
|
|
87
|
+
if (run.key !== void 0) parts.push(`key=${run.key}`);
|
|
88
|
+
if (run.status === "failed") parts.push(run.error);
|
|
89
|
+
return parts.join(" ");
|
|
90
|
+
}
|
|
91
|
+
/** `aai workflow show <runId>` — one run in full, including its output. */
|
|
92
|
+
async function executeWorkflowShow(cwd, runId, opts) {
|
|
93
|
+
const { api } = await target(cwd, opts);
|
|
94
|
+
const res = await attempt(() => api.get(runId));
|
|
95
|
+
if (!res.ok) return fail("workflow_show_failed", res.error, HINT_BROKER);
|
|
96
|
+
if (res.value === void 0) return fail("workflow_show_failed", `No run ${runId}`, HINT_BROKER);
|
|
97
|
+
const run = res.value;
|
|
98
|
+
log.info(formatRun(run));
|
|
99
|
+
if (run.status === "completed") log.info(JSON.stringify(run.output, null, 2));
|
|
100
|
+
return ok({ run });
|
|
101
|
+
}
|
|
102
|
+
/** `aai workflow cancel <runId>` — stop a live run. */
|
|
103
|
+
async function executeWorkflowCancel(cwd, runId, opts) {
|
|
104
|
+
const { api } = await target(cwd, opts);
|
|
105
|
+
const res = await attempt(() => api.cancel(runId));
|
|
106
|
+
if (!res.ok) return fail("workflow_cancel_failed", res.error, HINT_BROKER);
|
|
107
|
+
const cancelled = res.value;
|
|
108
|
+
log.info(cancelled ? `Cancelled ${runId}` : `${runId} had already finished`);
|
|
109
|
+
return ok({
|
|
110
|
+
runId,
|
|
111
|
+
cancelled
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The hint every failure here carries.
|
|
116
|
+
*
|
|
117
|
+
* Three causes dominate and they look similar from a terminal: the agent
|
|
118
|
+
* declares no workflows (404 from its own API), its sandbox is still booting
|
|
119
|
+
* (503 from the broker), or its operator closed the surface (401). Naming all
|
|
120
|
+
* three is cheap and cannot be wrong — the same reasoning
|
|
121
|
+
* `WORKFLOWS_UNAVAILABLE_MESSAGE` follows.
|
|
122
|
+
*/
|
|
123
|
+
const HINT_BROKER = "The agent may declare no workflows, or its sandbox may still be starting — try again shortly. Pass --token if the agent sets AAI_WORKFLOW_API_TOKEN.";
|
|
124
|
+
//#endregion
|
|
125
|
+
export { executeWorkflowCancel, executeWorkflowList, executeWorkflowRuns, executeWorkflowShow };
|