@alexkroman1/aai-cli 13.3.0 → 15.0.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-Clbq3a4h.mjs → _agent-BzUeqOdj.mjs} +32 -9
- package/dist/_agent.d.ts +23 -0
- package/dist/_artifacts-BJOYGQPp.mjs +21 -0
- package/dist/_artifacts.d.ts +16 -0
- package/dist/_build-target.d.ts +172 -0
- package/dist/{_bundler-DEkjO1d8.mjs → _bundler-DM0d0M7m.mjs} +8 -7
- package/dist/_cli-common.d.ts +45 -6
- package/dist/{_config-ZY2euhdh.mjs → _config-DYzC6WMD.mjs} +2 -2
- package/dist/_dev-env.d.ts +1 -1
- package/dist/{_dev-server-C13xuGB1.mjs → _dev-server-BzWB6-4y.mjs} +25 -24
- package/dist/_dev-vite-config.d.ts +3 -3
- package/dist/_e2e-test-utils.d.ts +1 -1
- package/dist/{_init-Ci4QGjp8.mjs → _init-Bsi3DZNJ.mjs} +9 -23
- package/dist/{_output-DbJt9gsl.mjs → _output-DBP9Op_d.mjs} +22 -13
- package/dist/_output.d.ts +10 -9
- package/dist/{_preflight-B2laWPdU.mjs → _preflight-CcAR577V.mjs} +2 -2
- package/dist/_resource-commands.d.ts +9 -9
- package/dist/_server-common-De0haHr9.mjs +70 -0
- package/dist/_server-common.d.ts +20 -1
- package/dist/{_slug-api-DlKpj91X.mjs → _slug-api-CGvc2YSQ.mjs} +18 -9
- package/dist/_slug-api.d.ts +19 -0
- package/dist/{_studio-DTi3EdXQ.mjs → _studio-DnR_BqFp.mjs} +7 -3
- package/dist/_studio-commands.d.ts +13 -13
- package/dist/{_templates-V4l5sZJy.mjs → _templates-CIlJ3Vay.mjs} +4 -4
- package/dist/_templates.d.ts +1 -1
- package/dist/{_typecheck-gate-sV4N5F93.mjs → _typecheck-gate-U3jcil8L.mjs} +3 -2
- package/dist/_typecheck-gate.d.ts +3 -1
- package/dist/{_utils-Dhd058D9.mjs → _utils-D5JGcjiW.mjs} +43 -1
- package/dist/_utils.d.ts +35 -0
- package/dist/_vercel-output.d.ts +63 -0
- package/dist/{_workflow-determinism-C9l8uC2R.mjs → _workflow-determinism-CvpqMpdh.mjs} +18 -26
- package/dist/_workflow-determinism.d.ts +3 -3
- package/dist/build-BhEaxBPu.mjs +481 -0
- package/dist/build.d.ts +23 -10
- package/dist/cli.d.ts +1 -2
- package/dist/cli.mjs +155 -138
- package/dist/{client-bundler-CT-_26c5.mjs → client-bundler-6mTLs6ny.mjs} +5 -5
- package/dist/client-bundler.d.ts +1 -1
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-RqlQZ6Y_.mjs → delete-BdFnbnVR.mjs} +4 -4
- package/dist/{deploy-B7f3CK7v.mjs → deploy-CGqPU5U-.mjs} +11 -11
- package/dist/{dev-DamXieW_.mjs → dev-Bx9gYBHM.mjs} +3 -3
- package/dist/{eval-h3DTVfRw.mjs → eval-B3I7FqN9.mjs} +3 -3
- package/dist/{init-D-vFrV8h.mjs → init-CFyusRbq.mjs} +48 -20
- package/dist/init.d.ts +14 -0
- package/dist/{login-CDiemNmC.mjs → login-DaLrPOFg.mjs} +4 -6
- package/dist/{logs-DGwPNCzB.mjs → logs-7BRwq0cG.mjs} +21 -14
- package/dist/project-config.mjs +1 -1
- package/dist/scaffold/CLAUDE.md +155 -76
- package/dist/scaffold/package.json +6 -6
- package/dist/{secret-V1w7y9-j.mjs → secret-Cjp912yF.mjs} +5 -5
- package/dist/secret.d.ts +8 -6
- package/dist/start.d.ts +112 -0
- package/dist/start.mjs +156 -0
- package/dist/{studio-BpMCfUNx.mjs → studio-C_zuRC_z.mjs} +13 -15
- package/dist/templates/briefing-desk/agent.eval.test.ts +156 -0
- package/dist/templates/call-audit/agent.test.ts +11 -6
- package/dist/templates/call-audit/agent.ts +2 -2
- package/dist/templates/call-audit/client.tsx +27 -42
- package/dist/templates/call-audit/workflows/audit.ts +7 -5
- package/dist/templates/call-audit/workflows/ingest.ts +7 -7
- package/dist/templates/call-audit/workflows/media.ts +12 -37
- package/dist/templates/call-audit/workflows/summarize.ts +8 -8
- package/dist/templates/call-audit/workflows/sync-api.ts +3 -3
- package/dist/templates/code-interpreter/agent.test.ts +103 -0
- package/dist/templates/dispatch-center/agent.test.ts +7 -7
- package/dist/templates/dispatch-center/client.tsx +53 -61
- package/dist/templates/dispatch-center/shared.ts +0 -8
- package/dist/templates/dispatch-center/tools/ops_dashboard.ts +4 -1
- package/dist/templates/embedded-assets/agent.eval.test.ts +4 -2
- package/dist/templates/health-assistant/agent.eval.test.ts +4 -2
- package/dist/templates/infocom-adventure/client.tsx +40 -36
- package/dist/templates/link-digest/agent.test.ts +3 -3
- package/dist/templates/link-digest/agent.ts +2 -2
- package/dist/templates/link-digest/client.tsx +81 -19
- package/dist/templates/link-digest/workflows/digest.ts +13 -16
- package/dist/templates/math-buddy/agent.test.ts +126 -0
- package/dist/templates/night-owl/agent.eval.test.ts +4 -2
- package/dist/templates/night-owl/client.tsx +8 -2
- package/dist/templates/personal-finance/agent.test.ts +127 -0
- package/dist/templates/pipeline-simple/agent.test.ts +2 -2
- package/dist/templates/pizza-ordering/client.tsx +5 -4
- package/dist/templates/pizza-ordering/shared.ts +3 -8
- package/dist/templates/pizza-ordering/tools/add_pizza.ts +3 -2
- package/dist/templates/pizza-ordering/tools/place_order.ts +3 -2
- package/dist/templates/pizza-ordering/tools/remove_pizza.ts +3 -2
- package/dist/templates/pizza-ordering/tools/update_pizza.ts +3 -2
- package/dist/templates/pizza-ordering/tools/view_order.ts +3 -2
- package/dist/templates/plan-and-execute/agent.test.ts +10 -5
- package/dist/templates/plan-and-execute/client.tsx +2 -2
- package/dist/templates/podcast-digest/agent.test.ts +20 -11
- package/dist/templates/podcast-digest/client.tsx +16 -22
- package/dist/templates/podcast-digest/workflows/digest.ts +21 -19
- package/dist/templates/podcast-digest/workflows/feeds.ts +61 -33
- package/dist/templates/podcast-digest/workflows/slack.ts +7 -7
- package/dist/templates/recap-workflow/agent.eval.test.ts +21 -13
- package/dist/templates/recap-workflow/agent.test.ts +27 -23
- package/dist/templates/recap-workflow/workflows/recap.ts +24 -28
- package/dist/templates/redline/agent.eval.test.ts +5 -8
- package/dist/templates/redline/agent.test.ts +1 -1
- package/dist/templates/redline/client.tsx +36 -34
- package/dist/templates/redline/workflows/redline.ts +17 -17
- package/dist/templates/research-workflow/agent.eval.test.ts +5 -5
- package/dist/templates/research-workflow/agent.test.ts +10 -7
- package/dist/templates/research-workflow/workflows/research.ts +28 -30
- package/dist/templates/retail/agent.test.ts +17 -15
- package/dist/templates/retail/cancel.ts +7 -6
- package/dist/templates/retail/client.tsx +39 -58
- package/dist/templates/retail/payment.ts +4 -3
- package/dist/templates/retail/pending.test.ts +19 -19
- package/dist/templates/retail/store.test.ts +5 -5
- package/dist/templates/retail/swap.ts +8 -11
- package/dist/templates/solo-rpg/agent.eval.test.ts +2 -16
- package/dist/templates/solo-rpg/agent.test.ts +12 -12
- package/dist/templates/solo-rpg/client.tsx +3 -3
- package/dist/templates/spoken-summary/agent.test.ts +9 -9
- package/dist/templates/spoken-summary/agent.ts +3 -3
- package/dist/templates/spoken-summary/client.tsx +23 -30
- package/dist/templates/spoken-summary/workflows/summarize.ts +11 -11
- package/dist/templates/spoken-summary/workflows/transcribe.ts +14 -14
- package/dist/templates/support-line/agent.ts +8 -0
- package/dist/templates/support-line/client.tsx +4 -3
- package/dist/templates/support-line/prompts.ts +0 -2
- package/dist/templates/transcription-workflow/agent.test.ts +20 -12
- package/dist/templates/transcription-workflow/agent.ts +2 -2
- package/dist/templates/transcription-workflow/client.tsx +15 -14
- package/dist/templates/transcription-workflow/recover.ts +1 -1
- package/dist/templates/transcription-workflow/run-panel.tsx +34 -14
- package/dist/templates/transcription-workflow/total-latency.tsx +46 -20
- package/dist/templates/transcription-workflow/workflows/batch.ts +15 -15
- package/dist/templates/transcription-workflow/workflows/downsample.ts +1 -1
- package/dist/templates/transcription-workflow/workflows/normalize.ts +15 -19
- package/dist/templates/transcription-workflow/workflows/stream.ts +12 -12
- package/dist/templates/transcription-workflow/workflows/sync-api.ts +3 -3
- package/dist/templates/transcription-workflow/workflows/transcribe.ts +23 -34
- package/dist/templates/travel-concierge/agent.eval.test.ts +2 -2
- package/dist/templates/travel-concierge/agent.test.ts +15 -7
- package/dist/templates/travel-concierge/client.tsx +2 -2
- package/dist/templates/travel-concierge/routing.ts +64 -55
- package/dist/templates/travel-concierge/shared.ts +10 -14
- package/dist/templates/travel-concierge/tools/cancel_action.ts +3 -1
- package/dist/templates/travel-concierge/tools/complete_or_escalate.ts +3 -1
- package/dist/templates/travel-concierge/tools/confirm_action.ts +3 -1
- package/dist/templates/travel-concierge/tools/lookup_booking.ts +4 -3
- package/dist/templates/travel-concierge/tools/search_car_rentals.ts +3 -2
- package/dist/templates/travel-concierge/tools/search_excursions.ts +3 -2
- package/dist/templates/travel-concierge/tools/search_flights.ts +3 -2
- package/dist/templates/travel-concierge/tools/search_hotels.ts +3 -2
- package/dist/templates/web-researcher/agent.test.ts +130 -0
- package/dist/{test-guenJUxi.mjs → test-D032V2cA.mjs} +4 -17
- package/dist/typecheck.mjs +1 -1
- package/dist/worker-bundler.d.ts +1 -1
- package/dist/worker-bundler.mjs +8 -8
- package/dist/{workflow-BZyKLkhV.mjs → workflow-CVioyO3V.mjs} +6 -5
- package/package.json +9 -4
- package/dist/_server-common-BV4_CrP3.mjs +0 -43
- package/dist/build-CWyFGe-W.mjs +0 -69
- package/dist/scaffold/server.mjs +0 -204
package/dist/typecheck.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { f as readPackageJson, n as binFromManifest, s as errorMessage } from "./_utils-D5JGcjiW.mjs";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
package/dist/worker-bundler.d.ts
CHANGED
|
@@ -34,4 +34,4 @@ export type BuildWorkerOptions = {
|
|
|
34
34
|
* @internal — build hook for aai-server/the studio; not a supported public
|
|
35
35
|
* API and not covered by semver.
|
|
36
36
|
*/
|
|
37
|
-
export declare function buildWorker(cwd: string,
|
|
37
|
+
export declare function buildWorker(cwd: string, options?: BuildWorkerOptions): Promise<string>;
|
package/dist/worker-bundler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { a as errorCode } from "./_utils-D5JGcjiW.mjs";
|
|
3
3
|
import { n as withPreservedNodeEnv } from "./_vite-env-kejF0p2L.mjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
@@ -92,8 +92,8 @@ export const __aaiConfig = {
|
|
|
92
92
|
...toAgentConfig(__aaiAgent),
|
|
93
93
|
toolSchemas: agentToolsToSchemas(__aaiAgent.tools ?? {}),
|
|
94
94
|
};
|
|
95
|
-
${runtime ? `export const __aaiCreateRuntime = (
|
|
96
|
-
createRuntime({ ...
|
|
95
|
+
${runtime ? `export const __aaiCreateRuntime = (options: Record<string, unknown>) =>
|
|
96
|
+
createRuntime({ ...options, agent: __aaiAgent });
|
|
97
97
|
` : ""}`;
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
@@ -105,21 +105,21 @@ ${runtime ? `export const __aaiCreateRuntime = (opts: Record<string, unknown>) =
|
|
|
105
105
|
* @internal — build hook for aai-server/the studio; not a supported public
|
|
106
106
|
* API and not covered by semver.
|
|
107
107
|
*/
|
|
108
|
-
async function buildWorker(cwd,
|
|
108
|
+
async function buildWorker(cwd, options = {}) {
|
|
109
109
|
const wrapperPath = path.join(cwd, WRAPPER_ENTRY_REL);
|
|
110
110
|
const [, toolFiles, systemPromptFile] = await Promise.all([
|
|
111
111
|
fs.mkdir(path.dirname(wrapperPath), { recursive: true }),
|
|
112
112
|
discoverToolFiles(cwd),
|
|
113
113
|
hasSystemPromptFile(cwd)
|
|
114
114
|
]);
|
|
115
|
-
await fs.writeFile(wrapperPath, wrapperEntrySource(
|
|
116
|
-
const plugins =
|
|
115
|
+
await fs.writeFile(wrapperPath, wrapperEntrySource(options.runtime !== false, toolFiles, systemPromptFile), "utf-8");
|
|
116
|
+
const plugins = options.plugins ?? [];
|
|
117
117
|
let result;
|
|
118
118
|
try {
|
|
119
119
|
result = await withPreservedNodeEnv(() => build({
|
|
120
120
|
root: cwd,
|
|
121
121
|
logLevel: "silent",
|
|
122
|
-
...
|
|
122
|
+
...options.configFile === false && { configFile: false },
|
|
123
123
|
...plugins.length > 0 && { plugins },
|
|
124
124
|
ssr: { noExternal: true },
|
|
125
125
|
build: {
|
|
@@ -130,7 +130,7 @@ async function buildWorker(cwd, opts = {}) {
|
|
|
130
130
|
fileName: "worker"
|
|
131
131
|
},
|
|
132
132
|
target: "node20",
|
|
133
|
-
minify:
|
|
133
|
+
minify: options.minify ? "oxc" : false,
|
|
134
134
|
write: false,
|
|
135
135
|
rollupOptions: { output: {
|
|
136
136
|
entryFileNames: "[name].js",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as ok, n as fail, t as CliError } from "./_output-
|
|
2
|
+
import { a as ok, n as fail, t as CliError } from "./_output-DBP9Op_d.mjs";
|
|
3
3
|
import { n as log } from "./_ui-DCt4qZrk.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { m as stripTrailingSlash } from "./_utils-D5JGcjiW.mjs";
|
|
5
|
+
import { i as readProjectConfig } from "./_config-DYzC6WMD.mjs";
|
|
6
|
+
import { n as getServerInfo } from "./_agent-BzUeqOdj.mjs";
|
|
6
7
|
import { errorMessage, omitUndefined } from "@alexkroman1/aai/utils";
|
|
7
8
|
import { createWorkflowApiClient } from "@alexkroman1/aai/workflow-api";
|
|
8
9
|
//#region src/workflow.ts
|
|
@@ -38,7 +39,7 @@ const DEFAULT_RUN_LIMIT = 20;
|
|
|
38
39
|
/**
|
|
39
40
|
* The base URL {@link createWorkflowApiClient} is given for `--agent`.
|
|
40
41
|
*
|
|
41
|
-
* A dev server has no slug: `
|
|
42
|
+
* A dev server has no slug: `createRuntimeServer` mounts the workflow API at
|
|
42
43
|
* `WORKFLOW_API_PREFIX` on the ORIGIN, where the platform serves it under
|
|
43
44
|
* `/:slug`. So targeting one is not a matter of a different origin — it is the
|
|
44
45
|
* absence of the path segment, which nothing in this command could express.
|
|
@@ -61,7 +62,7 @@ function agentBaseUrl(raw) {
|
|
|
61
62
|
const url = URL.parse(raw);
|
|
62
63
|
if (url === null) throw new CliError("bad_agent_url", `--agent is not a URL: ${JSON.stringify(raw)}`, HINT_URL);
|
|
63
64
|
if (url.protocol !== "http:" && url.protocol !== "https:") throw new CliError("bad_agent_url", `--agent must be http or https, not ${url.protocol.replace(":", "")}`, HINT_URL);
|
|
64
|
-
return raw
|
|
65
|
+
return stripTrailingSlash(raw);
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
68
|
* A client for the agent's workflow API, plus the bearer when one was given.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"@dev/source": "./src/project-config.ts",
|
|
39
39
|
"types": "./dist/project-config.d.ts",
|
|
40
40
|
"import": "./dist/project-config.mjs"
|
|
41
|
+
},
|
|
42
|
+
"./start": {
|
|
43
|
+
"@dev/source": "./src/start.ts",
|
|
44
|
+
"types": "./dist/start.d.ts",
|
|
45
|
+
"import": "./dist/start.mjs"
|
|
41
46
|
}
|
|
42
47
|
},
|
|
43
48
|
"dependencies": {
|
|
@@ -52,9 +57,9 @@
|
|
|
52
57
|
"p-timeout": "^7.0.1",
|
|
53
58
|
"vite": "^8.2.2",
|
|
54
59
|
"zod": "^4.5.4",
|
|
55
|
-
"@alexkroman1/aai": "
|
|
56
|
-
"@alexkroman1/aai-runtime": "
|
|
57
|
-
"@alexkroman1/aai-ui": "
|
|
60
|
+
"@alexkroman1/aai": "15.0.0",
|
|
61
|
+
"@alexkroman1/aai-runtime": "15.0.0",
|
|
62
|
+
"@alexkroman1/aai-ui": "15.0.0"
|
|
58
63
|
},
|
|
59
64
|
"devDependencies": {
|
|
60
65
|
"playwright": "^1.62.1",
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { i as errorCode } from "./_utils-Dhd058D9.mjs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { parseEnv } from "node:util";
|
|
5
|
-
import fs from "node:fs/promises";
|
|
6
|
-
//#region src/_server-common.ts
|
|
7
|
-
/**
|
|
8
|
-
* Build the `ctx.env` record that agent tools will see at runtime.
|
|
9
|
-
*
|
|
10
|
-
* Only variables explicitly declared in `.env` are included — matching
|
|
11
|
-
* the platform sandbox behavior where `ctx.env`
|
|
12
|
-
* contains only secrets set via `aai secret put`. This prevents agents
|
|
13
|
-
* from accidentally depending on shell-level vars (PATH, HOME, etc.) that
|
|
14
|
-
* won't exist in production.
|
|
15
|
-
*
|
|
16
|
-
* Values are resolved by merging the `.env` file with the current
|
|
17
|
-
* environment — existing shell exports take precedence over `.env`
|
|
18
|
-
* defaults, without mutating `process.env`.
|
|
19
|
-
*
|
|
20
|
-
* @param cwd - Project directory containing `.env` (optional).
|
|
21
|
-
* @param baseEnv - Override the environment to read values from (tests only).
|
|
22
|
-
*/
|
|
23
|
-
async function resolveServerEnv(cwd, baseEnv) {
|
|
24
|
-
let fileEntries = {};
|
|
25
|
-
if (cwd) {
|
|
26
|
-
let content = null;
|
|
27
|
-
try {
|
|
28
|
-
content = await fs.readFile(path.join(cwd, ".env"), "utf-8");
|
|
29
|
-
} catch (err) {
|
|
30
|
-
if (errorCode(err) !== "ENOENT") throw err;
|
|
31
|
-
}
|
|
32
|
-
if (content !== null) fileEntries = parseEnv(content);
|
|
33
|
-
}
|
|
34
|
-
const source = baseEnv ?? process.env;
|
|
35
|
-
const env = {};
|
|
36
|
-
for (const [key, fileVal] of Object.entries(fileEntries)) {
|
|
37
|
-
const val = source[key] ?? fileVal;
|
|
38
|
-
if (val !== void 0 && val !== "") env[key] = val;
|
|
39
|
-
}
|
|
40
|
-
return env;
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
|
-
export { resolveServerEnv as t };
|
package/dist/build-CWyFGe-W.mjs
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { a as ok, t as CliError } from "./_output-DbJt9gsl.mjs";
|
|
3
|
-
import { n as log, r as notify } from "./_ui-DCt4qZrk.mjs";
|
|
4
|
-
import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-DEkjO1d8.mjs";
|
|
5
|
-
import { assertTypechecks } from "./_typecheck-gate-sV4N5F93.mjs";
|
|
6
|
-
import { n as scanWorkflowDeterminism, t as determinismWarnings } from "./_workflow-determinism-C9l8uC2R.mjs";
|
|
7
|
-
import { TEST_FILES, classifyVitestError, runVitest } from "./test-guenJUxi.mjs";
|
|
8
|
-
import path from "node:path";
|
|
9
|
-
import fs from "node:fs/promises";
|
|
10
|
-
import { agentConfigWarnings } from "@alexkroman1/aai/manifest";
|
|
11
|
-
//#region src/build.ts
|
|
12
|
-
/**
|
|
13
|
-
* `aai build` — bundle the agent without deploying, behind the same gates
|
|
14
|
-
* deploy runs (tests, then typecheck), so the command previews the deploy
|
|
15
|
-
* artifact and its failures alike.
|
|
16
|
-
*
|
|
17
|
-
* It also LEAVES that artifact on disk, at {@link WORKER_ARTIFACT_REL}, which is
|
|
18
|
-
* what makes self-hosting work: `server.mjs` loads the built worker rather than
|
|
19
|
-
* `agent.ts`, because a tool is discovered by the bundler enumerating `tools/`
|
|
20
|
-
* and no un-bundled loader can see that directory. See the scaffold's own
|
|
21
|
-
* `server.mjs` and "Self-hosting runs the built worker" in
|
|
22
|
-
* `packages/aai-templates/CLAUDE.md`.
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* Where the built worker lands, relative to the project root — under `.aai/`,
|
|
26
|
-
* beside the built client, so one gitignore rule covers every build output.
|
|
27
|
-
*
|
|
28
|
-
* `server.mjs` hardcodes this path: it is a plain `.mjs` file in a user's
|
|
29
|
-
* project and may not import from the CLI (which a deployed project does not
|
|
30
|
-
* install at all). The pair is covered end-to-end by the `npm start` leg of
|
|
31
|
-
* `e2e.test.ts` — the only tier that runs both halves as a user does.
|
|
32
|
-
*/
|
|
33
|
-
const WORKER_ARTIFACT_REL = path.join(".aai", "worker.mjs");
|
|
34
|
-
/**
|
|
35
|
-
* Map a {@link runVitest} failure to a CliError — distinguishing a real test
|
|
36
|
-
* failure (test_failed) from the runner not spawning (spawn_failed) instead
|
|
37
|
-
* of a generic command_failed.
|
|
38
|
-
*/
|
|
39
|
-
function testGateError(err) {
|
|
40
|
-
const { code, message } = classifyVitestError(err);
|
|
41
|
-
return new CliError(code, message, "Re-run with --skipTests to build without tests", { cause: err });
|
|
42
|
-
}
|
|
43
|
-
async function executeBuild(opts) {
|
|
44
|
-
const { cwd } = opts;
|
|
45
|
-
if (!opts.skipTests) try {
|
|
46
|
-
runVitest(cwd, {
|
|
47
|
-
candidates: TEST_FILES,
|
|
48
|
-
all: true
|
|
49
|
-
});
|
|
50
|
-
} catch (err) {
|
|
51
|
-
throw testGateError(err);
|
|
52
|
-
}
|
|
53
|
-
if (!opts.skipTypecheck) await assertTypechecks(cwd);
|
|
54
|
-
const bundle = await buildAgentBundle(cwd, { minify: true });
|
|
55
|
-
const agentDef = await evalWorkerBundle(bundle.worker);
|
|
56
|
-
for (const warning of agentConfigWarnings(agentDef)) notify("warn", warning);
|
|
57
|
-
for (const warning of determinismWarnings(await scanWorkflowDeterminism(cwd))) notify("warn", warning);
|
|
58
|
-
const worker = path.join(cwd, WORKER_ARTIFACT_REL);
|
|
59
|
-
await fs.mkdir(path.dirname(worker), { recursive: true });
|
|
60
|
-
await fs.writeFile(worker, bundle.worker, "utf-8");
|
|
61
|
-
log.success("Build complete");
|
|
62
|
-
return ok({
|
|
63
|
-
name: agentDef.name,
|
|
64
|
-
workerBytes: bundle.worker.length,
|
|
65
|
-
worker
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
//#endregion
|
|
69
|
-
export { executeBuild };
|
package/dist/scaffold/server.mjs
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
// Self-hosted entrypoint — this is what `npm start` runs.
|
|
2
|
-
//
|
|
3
|
-
// It serves the agent over HTTP + WebSocket from your own Node process: no
|
|
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
|
-
//
|
|
8
|
-
// npm start # http://127.0.0.1:3000
|
|
9
|
-
// PORT=8080 HOST=0.0.0.0 npm start # bind every interface, e.g. in a container
|
|
10
|
-
//
|
|
11
|
-
// Anything that can run Node can host it: copy the project, install
|
|
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
|
-
|
|
15
|
-
import { existsSync } from "node:fs";
|
|
16
|
-
import { readFile } from "node:fs/promises";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
19
|
-
import { parseEnv } from "node:util";
|
|
20
|
-
import {
|
|
21
|
-
createAgentServer,
|
|
22
|
-
ensureSessionStateSchema,
|
|
23
|
-
ensureWorkflowJournalSchema,
|
|
24
|
-
withHostCredentialFallback,
|
|
25
|
-
} from "@alexkroman1/aai-runtime";
|
|
26
|
-
import { defaultClientDir } from "@alexkroman1/aai-ui/client-dir";
|
|
27
|
-
|
|
28
|
-
const root = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The built agent — `.aai/worker.mjs`, produced by `aai build`, which the
|
|
32
|
-
* `prestart` script runs for you. It is the SAME artifact `aai publish` uploads
|
|
33
|
-
* and the managed platform runs, so a self-hosted agent and a deployed one
|
|
34
|
-
* cannot behave differently.
|
|
35
|
-
*
|
|
36
|
-
* Loading the build rather than `agent.ts` directly is what makes `tools/`
|
|
37
|
-
* work. A tool is registered by EXISTING — its file name is the name the model
|
|
38
|
-
* calls, and nothing anywhere lists them — and the only place a directory can
|
|
39
|
-
* be turned into modules is where the bundle is assembled: a deployed agent is
|
|
40
|
-
* handed one ESM string and has no filesystem to scan. So the bundler
|
|
41
|
-
* enumerates `tools/` and emits the imports, and every loader that skips it
|
|
42
|
-
* would serve an agent with no tools at all.
|
|
43
|
-
*
|
|
44
|
-
* It also settles two things the bundler already resolves, and this file used
|
|
45
|
-
* to re-implement with `node:module` hooks: `import prompt from
|
|
46
|
-
* "./system-prompt.md?raw"` (a Vite convention — Node looks for a file
|
|
47
|
-
* literally named `system-prompt.md?raw`) and `import data from "./data.json"`
|
|
48
|
-
* with no import attribute (TypeScript's `resolveJsonModule` allows it, Node
|
|
49
|
-
* requires `with { type: "json" }`). Both are inlined into the bundle, so
|
|
50
|
-
* there is nothing left to teach Node.
|
|
51
|
-
*/
|
|
52
|
-
const workerPath = path.join(root, ".aai", "worker.mjs");
|
|
53
|
-
if (!existsSync(workerPath)) {
|
|
54
|
-
console.error(
|
|
55
|
-
`No built agent at ${path.relative(root, workerPath)}.\n` +
|
|
56
|
-
"Run `npm run build` (or `aai build`) first — `npm start` normally does it for you.",
|
|
57
|
-
);
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
// A file: URL rather than a relative specifier, so the path is correct on
|
|
61
|
-
// Windows, where a bare POSIX-looking path is not a valid module specifier.
|
|
62
|
-
const worker = await import(pathToFileURL(workerPath).href);
|
|
63
|
-
const agent = worker.default;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Parse a dotenv-syntax file into a record; `{}` when it does not exist.
|
|
67
|
-
*
|
|
68
|
-
* @param {string} file - Path relative to the project root.
|
|
69
|
-
* @returns {Promise<Record<string, string | undefined>>}
|
|
70
|
-
*/
|
|
71
|
-
async function readEnvFile(file) {
|
|
72
|
-
try {
|
|
73
|
-
return parseEnv(await readFile(path.join(root, file), "utf-8"));
|
|
74
|
-
} catch (err) {
|
|
75
|
-
// Absent is normal — `.env` is gitignored, and a container usually has
|
|
76
|
-
// neither file. Unreadable is not: the agent would boot with no
|
|
77
|
-
// credentials and fail later as an opaque provider auth error.
|
|
78
|
-
if (err.code !== "ENOENT") throw err;
|
|
79
|
-
return {};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Build `ctx.env` — what this agent's own tool code reads.
|
|
85
|
-
*
|
|
86
|
-
* The rule is the one `aai dev` follows: only DECLARED keys are exposed, and a
|
|
87
|
-
* real environment variable wins over the file's value. Nothing else from
|
|
88
|
-
* process.env comes along, so the agent cannot come to depend on a variable
|
|
89
|
-
* (PATH, HOME, …) that will not exist wherever you deploy it.
|
|
90
|
-
*
|
|
91
|
-
* `.env.example` counts as a declaration too, which is what lets a container
|
|
92
|
-
* run with no `.env` at all: the committed file names the secrets the agent
|
|
93
|
-
* needs, and `docker run -e MY_API_KEY=…` supplies the values. Declare
|
|
94
|
-
* `DATABASE_URL` the same way to give your tools `ctx.db`.
|
|
95
|
-
*/
|
|
96
|
-
async function resolveAgentEnv() {
|
|
97
|
-
const declared = { ...(await readEnvFile(".env.example")), ...(await readEnvFile(".env")) };
|
|
98
|
-
/** @type {Record<string, string>} */
|
|
99
|
-
const env = {};
|
|
100
|
-
for (const [key, fileValue] of Object.entries(declared)) {
|
|
101
|
-
const value = process.env[key] ?? fileValue;
|
|
102
|
-
// An empty value is worse than a missing one: a provider would try to
|
|
103
|
-
// authenticate with "" rather than report the credential as absent. The
|
|
104
|
-
// example file is full of them by design (`BRAVE_API_KEY=`). A key the
|
|
105
|
-
// parser saw with no value at all is the same case.
|
|
106
|
-
if (value !== undefined && value !== "") env[key] = value;
|
|
107
|
-
}
|
|
108
|
-
return env;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Static assets served at `/`: this project's own UI once `client.tsx` has been
|
|
113
|
-
* built (the same `aai build` leaves it in `.aai/client`), otherwise the
|
|
114
|
-
* prebuilt default client that ships inside @alexkroman1/aai-ui.
|
|
115
|
-
*/
|
|
116
|
-
function resolveClientDir() {
|
|
117
|
-
const built = path.join(root, ".aai", "client");
|
|
118
|
-
if (existsSync(path.join(built, "index.html"))) return built;
|
|
119
|
-
if (existsSync(path.join(root, "client.tsx"))) {
|
|
120
|
-
console.warn("client.tsx is not built — serving the default UI. Run `npm run build` first.");
|
|
121
|
-
}
|
|
122
|
-
return defaultClientDir();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const env = await resolveAgentEnv();
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Where THIS server is reachable from outside — `PUBLIC_URL`, e.g.
|
|
129
|
-
* `https://agent.example.com`. Set it whenever a durable workflow has to hand a
|
|
130
|
-
* URL to somebody else: `ctx.workflows.publicWebhookUrl(token)` is built from it,
|
|
131
|
-
* and without it that call throws rather than minting a `http://localhost:3000`
|
|
132
|
-
* URL that a payment provider will try, days later, and fail.
|
|
133
|
-
*
|
|
134
|
-
* Nothing else reads it, so it is not a startup requirement: an agent with no
|
|
135
|
-
* webhooks needs no value here. It is deliberately NOT derived from `PORT`/`HOST`
|
|
136
|
-
* — those describe the socket this process binds, which behind a reverse proxy is
|
|
137
|
-
* not what the outside world dials.
|
|
138
|
-
*/
|
|
139
|
-
const publicUrl = process.env.PUBLIC_URL?.trim();
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Create the session-state tables, when this agent has a database.
|
|
143
|
-
*
|
|
144
|
-
* A `DATABASE_URL` puts session state in Postgres, and those tables come with
|
|
145
|
-
* whoever OWNS the database — which for a self-hosted agent is you, with no
|
|
146
|
-
* migration step anywhere to hang them off. Without this the server starts,
|
|
147
|
-
* reports `sessionState: postgres, durable: true`, and then every session dies
|
|
148
|
-
* at start with a fatal error the browser shows as "Session failed to start",
|
|
149
|
-
* the real reason (`relation "aai_session_events" does not exist`) appearing
|
|
150
|
-
* only in this process's log.
|
|
151
|
-
*
|
|
152
|
-
* Best-effort: if a real migration already created them and this role may not
|
|
153
|
-
* CREATE, it warns and the server starts anyway.
|
|
154
|
-
*/
|
|
155
|
-
if (env.DATABASE_URL) {
|
|
156
|
-
await ensureSessionStateSchema({ url: env.DATABASE_URL, logger: console });
|
|
157
|
-
// And the durable-run journal's, which is a separate set of tables owned by
|
|
158
|
-
// the same deployment. Without it a project with a `DATABASE_URL` boots
|
|
159
|
-
// claiming durable runs and fails on the first one.
|
|
160
|
-
await ensureWorkflowJournalSchema({ url: env.DATABASE_URL, logger: console });
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const server = createAgentServer({
|
|
164
|
-
agent,
|
|
165
|
-
env,
|
|
166
|
-
// Provider credentials may ALSO arrive straight from the environment without
|
|
167
|
-
// being declared, and without becoming ctx.env — the ordinary way to hand
|
|
168
|
-
// ASSEMBLYAI_API_KEY to a container. Anything in `env` still wins.
|
|
169
|
-
providerEnv: withHostCredentialFallback(env),
|
|
170
|
-
clientDir: resolveClientDir(),
|
|
171
|
-
...(publicUrl ? { publicUrl } : {}),
|
|
172
|
-
// Durable workflows need nothing passed here. A `DATABASE_URL` in `env` puts
|
|
173
|
-
// the runs in Postgres and they survive a restart; without one they live in a
|
|
174
|
-
// per-process directory and do not, which is the same trade `aai dev` makes.
|
|
175
|
-
//
|
|
176
|
-
// Two options used to sit here — the compiled workflow surface, carried on the
|
|
177
|
-
// bundle as `__aaiWorkflowCode`/`__aaiStepCode` because a `"use workflow"` body
|
|
178
|
-
// had to go through a compiler at BUILD time. The engine reads the agent's own
|
|
179
|
-
// `workflows` declaration instead, so there is no artifact to hand over.
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// Loopback by default: this server has no request authentication of its own,
|
|
183
|
-
// so exposing it is a deliberate act. Set HOST=0.0.0.0 to bind every interface
|
|
184
|
-
// behind your own proxy or auth. An empty HOST means unset, not "everything".
|
|
185
|
-
const host = process.env.HOST?.trim() || undefined;
|
|
186
|
-
await server.listen(Number(process.env.PORT ?? 3000), host);
|
|
187
|
-
console.log(`${agent.name} listening on http://${host ?? "127.0.0.1"}:${server.port}`);
|
|
188
|
-
|
|
189
|
-
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
190
|
-
// A SYNCHRONOUS listener. An `async` one hands its promise to `process`,
|
|
191
|
-
// which discards what a listener returns — so a `close()` that rejects would
|
|
192
|
-
// surface as an unhandled rejection, i.e. a crash with a stack trace on
|
|
193
|
-
// Ctrl-C, instead of the non-zero exit a failed shutdown should be.
|
|
194
|
-
process.once(signal, () => {
|
|
195
|
-
// close() shuts the runtime down too — no separate runtime.shutdown().
|
|
196
|
-
server.close().then(
|
|
197
|
-
() => process.exit(0),
|
|
198
|
-
(error) => {
|
|
199
|
-
console.error(`shutdown failed: ${error?.message ?? error}`);
|
|
200
|
-
process.exit(1);
|
|
201
|
-
},
|
|
202
|
-
);
|
|
203
|
-
});
|
|
204
|
-
}
|