@alexkroman1/aai 0.10.4 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/{constants-BbAOvKl_.js → constants-CpLN9WGY.js} +2 -4
  2. package/dist/{direct-executor-BfHrDdPL.js → direct-executor-DyY-Y4ZE.js} +102 -324
  3. package/dist/host/_run-code.d.ts +35 -0
  4. package/dist/host/_runtime-conformance.d.ts +55 -0
  5. package/dist/{_test-utils.d.ts → host/_test-utils.d.ts} +7 -4
  6. package/dist/{builtin-tools.d.ts → host/builtin-tools.d.ts} +3 -3
  7. package/dist/{direct-executor.d.ts → host/direct-executor.d.ts} +7 -7
  8. package/dist/{internal.d.ts → host/index.d.ts} +5 -6
  9. package/dist/{internal.js → host/index.js} +15 -57
  10. package/dist/{matchers.js → host/matchers.js} +2 -2
  11. package/dist/{server.d.ts → host/server.d.ts} +1 -17
  12. package/dist/{server.js → host/server.js} +25 -22
  13. package/dist/{session.d.ts → host/session.d.ts} +7 -7
  14. package/dist/{testing.d.ts → host/testing.d.ts} +3 -3
  15. package/dist/host/testing.js +2 -0
  16. package/dist/{unstorage-kv.d.ts → host/unstorage-kv.d.ts} +1 -1
  17. package/dist/{vite-plugin.js → host/vite-plugin.js} +1 -1
  18. package/dist/{ws-handler.d.ts → host/ws-handler.d.ts} +1 -1
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +1 -1
  21. package/dist/isolate/_utils.d.ts +7 -0
  22. package/dist/isolate/_utils.js +17 -0
  23. package/dist/{constants.d.ts → isolate/constants.d.ts} +0 -2
  24. package/dist/{hooks.js → isolate/hooks.js} +1 -1
  25. package/dist/isolate/index.d.ts +19 -0
  26. package/dist/isolate/index.js +8 -0
  27. package/dist/{kv.js → isolate/kv.js} +2 -2
  28. package/dist/{protocol.js → isolate/protocol.js} +2 -2
  29. package/dist/{types.js → isolate/types.js} +1 -1
  30. package/dist/system-prompt-u19j6xfA.js +166 -0
  31. package/dist/{testing-BonJtfHJ.js → testing-CNNg2-n-.js} +22 -8
  32. package/package.json +40 -36
  33. package/dist/_run-code.d.ts +0 -31
  34. package/dist/_runtime-conformance.d.ts +0 -64
  35. package/dist/_utils.d.ts +0 -21
  36. package/dist/_utils.js +0 -49
  37. package/dist/testing.js +0 -2
  38. package/dist/{_mock-ws.d.ts → host/_mock-ws.d.ts} +0 -0
  39. package/dist/{matchers.d.ts → host/matchers.d.ts} +0 -0
  40. package/dist/{runtime.d.ts → host/runtime.d.ts} +0 -0
  41. package/dist/{s2s.d.ts → host/s2s.d.ts} +0 -0
  42. package/dist/{vite-plugin.d.ts → host/vite-plugin.d.ts} +0 -0
  43. package/dist/{_internal-types.d.ts → isolate/_internal-types.d.ts} +0 -0
  44. package/dist/{hooks.d.ts → isolate/hooks.d.ts} +0 -0
  45. package/dist/{kv.d.ts → isolate/kv.d.ts} +0 -0
  46. package/dist/{memory-tools.d.ts → isolate/memory-tools.d.ts} +0 -0
  47. package/dist/{protocol.d.ts → isolate/protocol.d.ts} +3 -3
  48. /package/dist/{system-prompt.d.ts → isolate/system-prompt.d.ts} +0 -0
  49. /package/dist/{types.d.ts → isolate/types.d.ts} +0 -0
@@ -1,4 +1,4 @@
1
- //#region constants.ts
1
+ //#region isolate/constants.ts
2
2
  /**
3
3
  * Centralised numeric constants — timeouts, size limits, sample rates.
4
4
  *
@@ -35,8 +35,6 @@ const MAX_VALUE_SIZE = 65536;
35
35
  const MAX_GLOB_PATTERN_LENGTH = 1024;
36
36
  /** Maximum conversation messages to retain (sliding window). */
37
37
  const DEFAULT_MAX_HISTORY = 200;
38
- /** Memory limit for run_code isolates (MB). */
39
- const RUN_CODE_MEMORY_MB = 32;
40
38
  /**
41
39
  * Content-Security-Policy applied to agent UI pages (both self-hosted and
42
40
  * platform). Single source of truth — used by `secureHeaders` middleware
@@ -44,4 +42,4 @@ const RUN_CODE_MEMORY_MB = 32;
44
42
  */
45
43
  const AGENT_CSP = "default-src 'self'; script-src 'self' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src 'self' wss: ws:; img-src 'self' data:; font-src 'self' https://fonts.gstatic.com; object-src 'none'; base-uri 'self'";
46
44
  //#endregion
47
- export { TOOL_EXECUTION_TIMEOUT_MS as _, DEFAULT_SHUTDOWN_TIMEOUT_MS as a, FETCH_TIMEOUT_MS as c, MAX_HTML_BYTES as d, MAX_PAGE_CHARS as f, RUN_CODE_TIMEOUT_MS as g, RUN_CODE_MEMORY_MB as h, DEFAULT_SESSION_START_TIMEOUT_MS as i, HOOK_TIMEOUT_MS as l, MAX_VALUE_SIZE as m, DEFAULT_IDLE_TIMEOUT_MS as n, DEFAULT_STT_SAMPLE_RATE as o, MAX_TOOL_RESULT_CHARS as p, DEFAULT_MAX_HISTORY as r, DEFAULT_TTS_SAMPLE_RATE as s, AGENT_CSP as t, MAX_GLOB_PATTERN_LENGTH as u };
45
+ export { DEFAULT_SHUTDOWN_TIMEOUT_MS as a, FETCH_TIMEOUT_MS as c, MAX_HTML_BYTES as d, MAX_PAGE_CHARS as f, TOOL_EXECUTION_TIMEOUT_MS as g, RUN_CODE_TIMEOUT_MS as h, DEFAULT_SESSION_START_TIMEOUT_MS as i, HOOK_TIMEOUT_MS as l, MAX_VALUE_SIZE as m, DEFAULT_IDLE_TIMEOUT_MS as n, DEFAULT_STT_SAMPLE_RATE as o, MAX_TOOL_RESULT_CHARS as p, DEFAULT_MAX_HISTORY as r, DEFAULT_TTS_SAMPLE_RATE as s, AGENT_CSP as t, MAX_GLOB_PATTERN_LENGTH as u };
@@ -1,321 +1,86 @@
1
- import { BuiltinToolSchema, DEFAULT_INSTRUCTIONS, ToolChoiceSchema, defineTool } from "./types.js";
2
- import { _ as TOOL_EXECUTION_TIMEOUT_MS, a as DEFAULT_SHUTDOWN_TIMEOUT_MS, c as FETCH_TIMEOUT_MS, d as MAX_HTML_BYTES, f as MAX_PAGE_CHARS, g as RUN_CODE_TIMEOUT_MS, l as HOOK_TIMEOUT_MS, m as MAX_VALUE_SIZE, o as DEFAULT_STT_SAMPLE_RATE, p as MAX_TOOL_RESULT_CHARS, s as DEFAULT_TTS_SAMPLE_RATE } from "./constants-BbAOvKl_.js";
3
- import { errorDetail, errorMessage, isReadOnlyFsOp, toolError } from "./_utils.js";
4
- import { callResolveTurnConfig, createAgentHooks } from "./hooks.js";
5
- import { ClientMessageSchema, buildReadyConfig } from "./protocol.js";
6
- import { matchGlob, sortAndPaginate } from "./kv.js";
1
+ import { i as EMPTY_PARAMS, n as memoryTools, o as agentToolsToSchemas, s as toAgentConfig, t as buildSystemPrompt } from "./system-prompt-u19j6xfA.js";
2
+ import { errorDetail, errorMessage, toolError } from "./isolate/_utils.js";
3
+ import { a as DEFAULT_SHUTDOWN_TIMEOUT_MS, c as FETCH_TIMEOUT_MS, d as MAX_HTML_BYTES, f as MAX_PAGE_CHARS, g as TOOL_EXECUTION_TIMEOUT_MS, h as RUN_CODE_TIMEOUT_MS, l as HOOK_TIMEOUT_MS, m as MAX_VALUE_SIZE, o as DEFAULT_STT_SAMPLE_RATE, p as MAX_TOOL_RESULT_CHARS, s as DEFAULT_TTS_SAMPLE_RATE } from "./constants-CpLN9WGY.js";
4
+ import { callResolveTurnConfig, createAgentHooks } from "./isolate/hooks.js";
5
+ import { matchGlob, sortAndPaginate } from "./isolate/kv.js";
6
+ import { ClientMessageSchema, buildReadyConfig } from "./isolate/protocol.js";
7
7
  import { z } from "zod";
8
- import WsWebSocket from "ws";
9
8
  import pTimeout from "p-timeout";
10
9
  import { createStorage, prefixStorage } from "unstorage";
10
+ import vm from "node:vm";
11
11
  import { createNanoEvents } from "nanoevents";
12
- //#region runtime.ts
13
- /**
14
- * Runtime dependencies injected into the session pipeline.
15
- *
16
- * Defines the {@link Logger} interface, a default {@link consoleLogger},
17
- * and the {@link S2SConfig} for Speech-to-Speech endpoint configuration.
18
- */
19
- /** Default console-backed logger. */
20
- const consoleLogger = {
21
- info: (msg, ctx) => ctx ? console.log(msg, ctx) : console.log(msg),
22
- warn: (msg, ctx) => ctx ? console.warn(msg, ctx) : console.warn(msg),
23
- error: (msg, ctx) => ctx ? console.error(msg, ctx) : console.error(msg),
24
- debug: (msg, ctx) => ctx ? console.debug(msg, ctx) : console.debug(msg)
25
- };
26
- /**
27
- * Structured JSON logger for production diagnostics. Each log entry is a
28
- * single-line JSON object with `timestamp`, `level`, `msg`, and any
29
- * caller-provided context fields.
30
- */
31
- function jsonLog(level) {
32
- return (msg, ctx) => {
33
- const entry = {
34
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
35
- level,
36
- msg
37
- };
38
- if (ctx) Object.assign(entry, ctx);
39
- (level === "error" || level === "warn" ? process.stderr : process.stdout).write(`${JSON.stringify(entry)}\n`);
40
- };
41
- }
42
- const jsonLogger = {
43
- info: jsonLog("info"),
44
- warn: jsonLog("warn"),
45
- error: jsonLog("error"),
46
- debug: jsonLog("debug")
47
- };
48
- /** Default S2S endpoint configuration. */
49
- const DEFAULT_S2S_CONFIG = {
50
- wssUrl: "wss://speech-to-speech.us.assemblyai.com/v1/realtime",
51
- inputSampleRate: DEFAULT_STT_SAMPLE_RATE,
52
- outputSampleRate: DEFAULT_TTS_SAMPLE_RATE
53
- };
54
- //#endregion
55
- //#region _internal-types.ts
56
- /**
57
- * Zod schema for serializable agent configuration sent over the wire.
58
- *
59
- * This is the JSON-safe subset of the agent definition that can be
60
- * transmitted between the worker and the host process via structured clone.
61
- */
62
- const AgentConfigSchema = z.object({
63
- name: z.string().min(1),
64
- instructions: z.string(),
65
- greeting: z.string(),
66
- sttPrompt: z.string().optional(),
67
- maxSteps: z.number().int().positive().optional(),
68
- toolChoice: ToolChoiceSchema.optional(),
69
- builtinTools: z.array(BuiltinToolSchema).readonly().optional(),
70
- idleTimeoutMs: z.number().nonnegative().optional()
71
- });
72
- /** Extract the serializable {@link AgentConfig} subset from a source object. */
73
- function toAgentConfig(src) {
74
- const config = {
75
- name: src.name,
76
- instructions: src.instructions,
77
- greeting: src.greeting
78
- };
79
- if (src.sttPrompt !== void 0) config.sttPrompt = src.sttPrompt;
80
- if (typeof src.maxSteps !== "function" && src.maxSteps !== void 0) config.maxSteps = src.maxSteps;
81
- if (src.toolChoice !== void 0) config.toolChoice = src.toolChoice;
82
- if (src.builtinTools) config.builtinTools = [...src.builtinTools];
83
- if (src.idleTimeoutMs !== void 0) config.idleTimeoutMs = src.idleTimeoutMs;
84
- return config;
85
- }
86
- /**
87
- * Zod schema for serialized tool definitions sent over the wire.
88
- *
89
- * `parameters` must be a valid JSON Schema object (with `type`, `properties`,
90
- * etc.) — the Vercel AI SDK wraps it via `jsonSchema()`.
91
- */
92
- const ToolSchemaSchema = z.object({
93
- name: z.string().min(1),
94
- description: z.string().min(1),
95
- parameters: z.record(z.string(), z.unknown())
96
- });
97
- /** Empty Zod object schema used as default when tools have no parameters. */
98
- const EMPTY_PARAMS = z.object({});
99
- /**
100
- * Convert agent tool definitions to JSON Schema format for wire transport.
101
- *
102
- * Transforms the Zod-based `parameters` of each tool into a plain JSON Schema
103
- * object suitable for structured clone / JSON serialization.
104
- */
105
- function agentToolsToSchemas(tools) {
106
- return Object.entries(tools).map(([name, def]) => ({
107
- name,
108
- description: def.description,
109
- parameters: z.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
110
- }));
111
- }
112
- //#endregion
113
- //#region _run-code.ts
12
+ import WsWebSocket from "ws";
13
+ //#region host/_run-code.ts
114
14
  /**
115
- * run_code built-in tool — executes user JavaScript in a fresh secure-exec
116
- * V8 isolate with no network, filesystem writes, or env access.
15
+ * run_code built-in tool — executes user JavaScript in a fresh `node:vm`
16
+ * context with no network, filesystem, or process access.
117
17
  */
118
18
  const runCodeParams = z.object({ code: z.string().describe("JavaScript code to execute. Use console.log() for output.") });
119
19
  /**
120
- * Execute JavaScript code inside a fresh secure-exec V8 isolate.
20
+ * Execute JavaScript code inside a fresh `node:vm` context.
121
21
  *
122
- * Each invocation spins up a disposable isolate with:
123
- * - No filesystem writes
124
- * - No network access
22
+ * Each invocation creates a disposable VM context with:
23
+ * - No filesystem access (`node:fs` and other built-ins unavailable)
24
+ * - No network access (`fetch`, `http` unavailable)
125
25
  * - No child process spawning
126
- * - No environment variable access
127
- * - 32 MB memory limit
128
- * - 5 second execution timeout
26
+ * - No environment variable access (`process` unavailable)
27
+ * - Execution timeout (default 5 s)
129
28
  *
130
- * The isolate is disposed immediately after execution, so no state
131
- * leaks between invocations or across sessions.
29
+ * The context is discarded after execution, so no state leaks between
30
+ * invocations or across sessions.
132
31
  */
133
32
  function createRunCode() {
134
33
  return {
135
- description: "Execute JavaScript code in a secure sandbox and return the output. Use this for calculations, data transformations, string manipulation, or any task that benefits from running code. Output is captured from console.log(). No network or filesystem access.",
34
+ description: "Execute JavaScript code in a sandbox and return the output. Use this for calculations, data transformations, string manipulation, or any task that benefits from running code. Output is captured from console.log(). No network or filesystem access.",
136
35
  parameters: runCodeParams,
137
36
  async execute(args) {
138
37
  return executeInIsolate(args.code);
139
38
  }
140
39
  };
141
40
  }
142
- /** Lazily import secure-exec to avoid top-level side effects. */
143
- let _secureExecPromise;
144
- function getSecureExec() {
145
- _secureExecPromise ??= import("secure-exec");
146
- return _secureExecPromise;
147
- }
148
- const RUN_CODE_HARNESS = `
149
- import { readFileSync } from "node:fs";
150
-
151
- const __output = [];
152
- const __capture = (...args) => __output.push(args.map(String).join(" "));
153
- const __console = {
154
- log: __capture, info: __capture, warn: __capture,
155
- error: __capture, debug: __capture,
156
- };
157
- try {
158
- const __userCode = readFileSync("/app/user-code.js", "utf8");
159
- const __AsyncFn = Object.getPrototypeOf(async function(){}).constructor;
160
- const __fn = new __AsyncFn("console", __userCode);
161
- await __fn(__console);
162
- const result = __output.join("\\n").trim();
163
- process.stdout.write(JSON.stringify({ ok: true, result: result || "Code ran successfully (no output)" }));
164
- } catch (err) {
165
- process.stdout.write(JSON.stringify({ ok: false, error: String(err?.message ?? err) }));
166
- }
167
- `;
168
- const IsolateOutputSchema = z.object({
169
- ok: z.boolean(),
170
- result: z.string().optional(),
171
- error: z.string().optional()
172
- });
173
- /** Parse stdout from the run_code harness into a result or error. */
174
- function parseIsolateOutput(stdout, stderr) {
175
- if (!stdout) {
176
- if (stderr) return { error: stderr.trim() };
177
- return { error: "Code execution timed out" };
178
- }
179
- try {
180
- const parsed = IsolateOutputSchema.parse(JSON.parse(stdout));
181
- if (parsed.ok) return parsed.result ?? "Code ran successfully (no output)";
182
- return { error: parsed.error ?? "Unknown error" };
183
- } catch {
184
- return stdout.trim() || "Code ran successfully (no output)";
185
- }
186
- }
187
41
  /**
188
- * Exported for testing — execute user code in a fresh secure-exec V8 isolate.
42
+ * Execute user code in a fresh `node:vm` context.
43
+ *
44
+ * @remarks
45
+ * The VM context only exposes standard ECMAScript globals and a console
46
+ * object that captures output. Node.js APIs (`process`, `require`,
47
+ * `import()`) are not available inside the sandbox.
189
48
  */
190
49
  async function executeInIsolate(code) {
191
- const { createInMemoryFileSystem, createNodeDriver, createNodeRuntimeDriverFactory, NodeRuntime } = await getSecureExec();
192
- const fs = createInMemoryFileSystem();
193
- await fs.writeFile("/app/harness.js", RUN_CODE_HARNESS);
194
- await fs.writeFile("/app/user-code.js", code);
195
- const stdoutChunks = [];
196
- const stderrChunks = [];
197
- let resolveOutput = null;
198
- const outputReady = new Promise((r) => {
199
- resolveOutput = r;
200
- });
201
- const runtime = new NodeRuntime({
202
- systemDriver: createNodeDriver({
203
- filesystem: fs,
204
- permissions: {
205
- fs: (req) => isReadOnlyFsOp(req.op) ? { allow: true } : {
206
- allow: false,
207
- reason: "Filesystem is read-only"
208
- },
209
- network: () => ({
210
- allow: false,
211
- reason: "Network access is disabled in run_code"
212
- }),
213
- childProcess: () => ({
214
- allow: false,
215
- reason: "Subprocess spawning is disabled"
216
- }),
217
- env: () => ({
218
- allow: false,
219
- reason: "Env access is disabled in run_code"
220
- })
221
- }
222
- }),
223
- runtimeDriverFactory: createNodeRuntimeDriverFactory(),
224
- memoryLimit: 32,
225
- onStdio(event) {
226
- if (event.channel === "stdout") stdoutChunks.push(event.message);
227
- if (event.channel === "stderr") stderrChunks.push(event.message);
228
- resolveOutput?.();
229
- }
50
+ const output = [];
51
+ const capture = (...args) => output.push(args.map(String).join(" "));
52
+ const context = vm.createContext({
53
+ console: {
54
+ log: capture,
55
+ info: capture,
56
+ warn: capture,
57
+ error: capture,
58
+ debug: capture
59
+ },
60
+ setTimeout,
61
+ clearTimeout,
62
+ setInterval,
63
+ clearInterval,
64
+ URL,
65
+ URLSearchParams,
66
+ TextEncoder,
67
+ TextDecoder,
68
+ atob,
69
+ btoa,
70
+ structuredClone,
71
+ queueMicrotask
230
72
  });
231
- const execPromise = runtime.exec("import \"/app/harness.js\";", { cwd: "/app" });
232
73
  try {
233
- await Promise.race([outputReady, new Promise((r) => setTimeout(r, RUN_CODE_TIMEOUT_MS))]);
234
- await Promise.race([execPromise.catch(() => {}), new Promise((r) => setTimeout(r, 200))]);
235
- return parseIsolateOutput(stdoutChunks.join(""), stderrChunks.join(""));
74
+ const wrapped = `(async () => {\n${code}\n})()`;
75
+ const promise = new vm.Script(wrapped, { filename: "run_code.js" }).runInContext(context, { timeout: RUN_CODE_TIMEOUT_MS });
76
+ await Promise.race([promise, new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("Code execution timed out")), RUN_CODE_TIMEOUT_MS))]);
77
+ return output.join("\n").trim() || "Code ran successfully (no output)";
236
78
  } catch (err) {
237
79
  return { error: errorMessage(err) };
238
- } finally {
239
- runtime.dispose();
240
80
  }
241
81
  }
242
82
  //#endregion
243
- //#region memory-tools.ts
244
- /**
245
- * KV-backed memory tools for agent persistent state.
246
- */
247
- /**
248
- * Returns a standard set of KV-backed memory tools: `save_memory`,
249
- * `recall_memory`, `list_memories`, and `forget_memory`.
250
- *
251
- * Spread the result into your agent's `tools` record.
252
- *
253
- * @example
254
- * ```ts
255
- * import { defineAgent, memoryTools } from "aai";
256
- *
257
- * export default defineAgent({
258
- * name: "My Agent",
259
- * tools: { ...memoryTools() },
260
- * });
261
- * ```
262
- *
263
- * @returns A record with four tool definitions: `save_memory`, `recall_memory`,
264
- * `list_memories`, and `forget_memory`.
265
- * @public
266
- */
267
- function memoryTools() {
268
- return {
269
- save_memory: defineTool({
270
- description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
271
- parameters: z.object({
272
- key: z.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
273
- value: z.string().describe("The information to remember")
274
- }),
275
- execute: async ({ key, value }, ctx) => {
276
- await ctx.kv.set(key, value);
277
- return { saved: key };
278
- }
279
- }),
280
- recall_memory: defineTool({
281
- description: "Retrieve a previously saved memory by its key.",
282
- parameters: z.object({ key: z.string().describe("The key to look up") }),
283
- execute: async ({ key }, ctx) => {
284
- const value = await ctx.kv.get(key);
285
- if (value === null) return {
286
- found: false,
287
- key
288
- };
289
- return {
290
- found: true,
291
- key,
292
- value
293
- };
294
- }
295
- }),
296
- list_memories: defineTool({
297
- description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
298
- parameters: z.object({ prefix: z.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional() }),
299
- execute: async ({ prefix }, ctx) => {
300
- const entries = await ctx.kv.list(prefix ?? "");
301
- return {
302
- count: entries.length,
303
- keys: entries.map((e) => e.key)
304
- };
305
- }
306
- }),
307
- forget_memory: defineTool({
308
- description: "Delete a previously saved memory by its key.",
309
- parameters: z.object({ key: z.string().describe("The key to delete") }),
310
- execute: async ({ key }, ctx) => {
311
- await ctx.kv.delete(key);
312
- return { deleted: key };
313
- }
314
- })
315
- };
316
- }
317
- //#endregion
318
- //#region builtin-tools.ts
83
+ //#region host/builtin-tools.ts
319
84
  /**
320
85
  * Built-in tool definitions for the AAI agent SDK.
321
86
  *
@@ -477,7 +242,50 @@ function getBuiltinToolSchemas(names) {
477
242
  })));
478
243
  }
479
244
  //#endregion
480
- //#region s2s.ts
245
+ //#region host/runtime.ts
246
+ /**
247
+ * Runtime dependencies injected into the session pipeline.
248
+ *
249
+ * Defines the {@link Logger} interface, a default {@link consoleLogger},
250
+ * and the {@link S2SConfig} for Speech-to-Speech endpoint configuration.
251
+ */
252
+ /** Default console-backed logger. */
253
+ const consoleLogger = {
254
+ info: (msg, ctx) => ctx ? console.log(msg, ctx) : console.log(msg),
255
+ warn: (msg, ctx) => ctx ? console.warn(msg, ctx) : console.warn(msg),
256
+ error: (msg, ctx) => ctx ? console.error(msg, ctx) : console.error(msg),
257
+ debug: (msg, ctx) => ctx ? console.debug(msg, ctx) : console.debug(msg)
258
+ };
259
+ /**
260
+ * Structured JSON logger for production diagnostics. Each log entry is a
261
+ * single-line JSON object with `timestamp`, `level`, `msg`, and any
262
+ * caller-provided context fields.
263
+ */
264
+ function jsonLog(level) {
265
+ return (msg, ctx) => {
266
+ const entry = {
267
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
268
+ level,
269
+ msg
270
+ };
271
+ if (ctx) Object.assign(entry, ctx);
272
+ (level === "error" || level === "warn" ? process.stderr : process.stdout).write(`${JSON.stringify(entry)}\n`);
273
+ };
274
+ }
275
+ const jsonLogger = {
276
+ info: jsonLog("info"),
277
+ warn: jsonLog("warn"),
278
+ error: jsonLog("error"),
279
+ debug: jsonLog("debug")
280
+ };
281
+ /** Default S2S endpoint configuration. */
282
+ const DEFAULT_S2S_CONFIG = {
283
+ wssUrl: "wss://speech-to-speech.us.assemblyai.com/v1/realtime",
284
+ inputSampleRate: DEFAULT_STT_SAMPLE_RATE,
285
+ outputSampleRate: DEFAULT_TTS_SAMPLE_RATE
286
+ };
287
+ //#endregion
288
+ //#region host/s2s.ts
481
289
  const uint8ToBase64 = (bytes) => Buffer.from(bytes).toString("base64");
482
290
  const base64ToUint8 = (base64) => new Uint8Array(Buffer.from(base64, "base64"));
483
291
  const WS_OPEN = 1;
@@ -726,37 +534,7 @@ function connectS2s(opts) {
726
534
  });
727
535
  }
728
536
  //#endregion
729
- //#region system-prompt.ts
730
- function getFormattedDate() {
731
- return (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
732
- weekday: "long",
733
- year: "numeric",
734
- month: "long",
735
- day: "numeric"
736
- });
737
- }
738
- const VOICE_RULES = "\n\nCRITICAL OUTPUT RULES — you MUST follow these for EVERY response:\nYour response will be spoken aloud by a TTS system and displayed as plain text.\n- NEVER use markdown: no **, no *, no _, no #, no `, no [](), no ---\n- NEVER use bullet points (-, *, •) or numbered lists (1., 2.)\n- NEVER use code blocks or inline code\n- NEVER mention tools, search, APIs, or technical failures to the user. If a tool returns no results, just answer naturally without explaining why.\n- Write exactly as you would say it out loud to a friend\n- Use short conversational sentences. To list things, say \"First,\" \"Next,\" \"Finally,\"\n- Keep responses concise — 1 to 3 sentences max";
739
- /**
740
- * Build the system prompt sent to the LLM from the agent configuration.
741
- *
742
- * Assembles the default instructions, today's date, agent-specific instructions,
743
- * and optional sections for tool usage preamble and voice output rules.
744
- *
745
- * @param config - The serializable agent configuration (name, instructions, etc.).
746
- * @param opts.hasTools - When `true`, appends a preamble instructing the LLM to
747
- * speak a brief phrase before each tool call to fill silence.
748
- * @param opts.voice - When `true`, appends strict voice-specific output rules
749
- * (no markdown, no bullet points, conversational tone, concise responses).
750
- * @returns The assembled system prompt string.
751
- */
752
- function buildSystemPrompt(config, opts) {
753
- const { hasTools } = opts;
754
- const agentInstructions = config.instructions && config.instructions !== DEFAULT_INSTRUCTIONS ? `\n\nAgent-Specific Instructions:\n${config.instructions}` : "";
755
- const toolPreamble = hasTools ? "\n\nWhen you decide to use a tool, ALWAYS say a brief natural phrase BEFORE the tool call (e.g. \"Let me look that up\" or \"One moment while I check\"). This fills silence while the tool executes. Keep preambles to one short sentence." : "";
756
- return DEFAULT_INSTRUCTIONS + `\n\nToday's date is ${getFormattedDate()}.` + agentInstructions + toolPreamble + (opts.voice ? VOICE_RULES : "");
757
- }
758
- //#endregion
759
- //#region session.ts
537
+ //#region host/session.ts
760
538
  function buildCtx(opts) {
761
539
  const { id, agentConfig, hooks, log } = opts;
762
540
  const maxHistory = opts.maxHistory ?? 200;
@@ -1149,7 +927,7 @@ function createS2sSession(opts) {
1149
927
  };
1150
928
  }
1151
929
  //#endregion
1152
- //#region unstorage-kv.ts
930
+ //#region host/unstorage-kv.ts
1153
931
  /**
1154
932
  * Key-value store backed by unstorage.
1155
933
  *
@@ -1210,7 +988,7 @@ function createUnstorageKv(options) {
1210
988
  };
1211
989
  }
1212
990
  //#endregion
1213
- //#region ws-handler.ts
991
+ //#region host/ws-handler.ts
1214
992
  /**
1215
993
  * WebSocket session lifecycle handler.
1216
994
  *
@@ -1400,7 +1178,7 @@ function wireSessionSocket(ws, opts) {
1400
1178
  });
1401
1179
  }
1402
1180
  //#endregion
1403
- //#region direct-executor.ts
1181
+ //#region host/direct-executor.ts
1404
1182
  /**
1405
1183
  * Agent runtime — the execution engine for voice agents.
1406
1184
  *
@@ -1586,4 +1364,4 @@ function createRuntime(opts) {
1586
1364
  };
1587
1365
  }
1588
1366
  //#endregion
1589
- export { consoleLogger as _, _internals as a, buildSystemPrompt as c, AgentConfigSchema as d, EMPTY_PARAMS as f, DEFAULT_S2S_CONFIG as g, toAgentConfig as h, createUnstorageKv as i, connectS2s as l, agentToolsToSchemas as m, executeToolCall as n, buildCtx as o, ToolSchemaSchema as p, wireSessionSocket as r, createS2sSession as s, createRuntime as t, defaultCreateS2sWebSocket as u, jsonLogger as v };
1367
+ export { _internals as a, connectS2s as c, consoleLogger as d, jsonLogger as f, createUnstorageKv as i, defaultCreateS2sWebSocket as l, executeToolCall as n, buildCtx as o, wireSessionSocket as r, createS2sSession as s, createRuntime as t, DEFAULT_S2S_CONFIG as u };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * run_code built-in tool — executes user JavaScript in a fresh `node:vm`
3
+ * context with no network, filesystem, or process access.
4
+ */
5
+ import { z } from "zod";
6
+ import type { ToolDef } from "../isolate/types.ts";
7
+ declare const runCodeParams: z.ZodObject<{
8
+ code: z.ZodString;
9
+ }, z.core.$strip>;
10
+ /**
11
+ * Execute JavaScript code inside a fresh `node:vm` context.
12
+ *
13
+ * Each invocation creates a disposable VM context with:
14
+ * - No filesystem access (`node:fs` and other built-ins unavailable)
15
+ * - No network access (`fetch`, `http` unavailable)
16
+ * - No child process spawning
17
+ * - No environment variable access (`process` unavailable)
18
+ * - Execution timeout (default 5 s)
19
+ *
20
+ * The context is discarded after execution, so no state leaks between
21
+ * invocations or across sessions.
22
+ */
23
+ export declare function createRunCode(): ToolDef<typeof runCodeParams>;
24
+ /**
25
+ * Execute user code in a fresh `node:vm` context.
26
+ *
27
+ * @remarks
28
+ * The VM context only exposes standard ECMAScript globals and a console
29
+ * object that captures output. Node.js APIs (`process`, `require`,
30
+ * `import()`) are not available inside the sandbox.
31
+ */
32
+ export declare function executeInIsolate(code: string): Promise<string | {
33
+ error: string;
34
+ }>;
35
+ export {};
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared runtime conformance tests.
3
+ *
4
+ * Both the self-hosted direct executor and the platform sandbox must satisfy
5
+ * the same behavioral contract. This module defines that contract as a
6
+ * reusable test suite that can be wired to either runtime.
7
+ *
8
+ * Inspired by Nitro's `testNitro()` pattern: one test fixture, many runtimes.
9
+ *
10
+ * @example Direct executor (unit test)
11
+ * ```ts
12
+ * import { testRuntime } from "./_runtime-conformance.ts";
13
+ *
14
+ * testRuntime("direct", () => {
15
+ * const exec = createRuntime({ agent: CONFORMANCE_AGENT, env: { MY_VAR: "test-value" } });
16
+ * return { executeTool: exec.executeTool, hooks: exec.hooks };
17
+ * });
18
+ * ```
19
+ *
20
+ * @example Sandbox (integration test in aai-server)
21
+ * ```ts
22
+ * import { testRuntime } from "@alexkroman1/aai/host";
23
+ *
24
+ * testRuntime("sandbox", async () => {
25
+ * // ... start isolate with a bundled agent
26
+ * return { executeTool: buildExecuteTool(...), hooks: buildHookInvoker(...) };
27
+ * });
28
+ * ```
29
+ */
30
+ import type { ExecuteTool } from "../isolate/_internal-types.ts";
31
+ import type { AgentHooks } from "../isolate/hooks.ts";
32
+ import { type AgentDef } from "../isolate/types.ts";
33
+ /**
34
+ * Minimal runtime surface needed for conformance tests.
35
+ *
36
+ * Both `Runtime` and `buildExecuteTool`/`buildHookInvoker` from the
37
+ * sandbox produce objects that satisfy this interface.
38
+ */
39
+ export type RuntimeTestContext = {
40
+ executeTool: ExecuteTool;
41
+ hooks: AgentHooks;
42
+ };
43
+ /** Agent definition used by the conformance suite (direct executor path). */
44
+ export declare const CONFORMANCE_AGENT: AgentDef;
45
+ /**
46
+ * Run the runtime conformance test suite against a given runtime context.
47
+ *
48
+ * The `getContext` callback is invoked once per test to retrieve the
49
+ * current {@link RuntimeTestContext}. This allows the caller to set up
50
+ * the runtime in a `beforeAll` and return it lazily.
51
+ *
52
+ * All tests assume the runtime was created with {@link CONFORMANCE_AGENT}
53
+ * (or its bundle equivalent) and `env: { MY_VAR: "test-value" }`.
54
+ */
55
+ export declare function testRuntime(label: string, getContext: () => RuntimeTestContext): void;
@@ -1,14 +1,17 @@
1
- import type { AgentConfig } from "./_internal-types.ts";
2
- import type { ClientSink } from "./protocol.ts";
1
+ import type { AgentConfig } from "../isolate/_internal-types.ts";
2
+ import type { ClientSink } from "../isolate/protocol.ts";
3
+ import type { AgentDef, ToolContext, ToolDef } from "../isolate/types.ts";
3
4
  import type { S2sEvents, S2sHandle } from "./s2s.ts";
5
+ import type { Session } from "./session.ts";
4
6
  import { type S2sSessionOptions } from "./session.ts";
5
- import type { AgentDef, ToolContext, ToolDef } from "./types.ts";
6
7
  /** Yield to the microtask queue so pending promises settle. */
7
8
  export declare function flush(): Promise<void>;
8
9
  export declare function createMockToolContext(overrides?: Partial<ToolContext>): ToolContext;
9
10
  export declare function makeTool(overrides?: Partial<ToolDef>): ToolDef;
10
11
  export declare function makeAgent(overrides?: Partial<AgentDef>): AgentDef;
11
12
  export declare function makeConfig(overrides?: Partial<AgentConfig>): AgentConfig;
13
+ /** Create a stub Session with all methods as vi.fn() spies. */
14
+ export declare function makeStubSession(overrides?: Partial<Session>): Session;
12
15
  export type MockS2sHandle = S2sHandle & {
13
16
  _fire: <K extends keyof S2sEvents>(type: K, ...args: Parameters<S2sEvents[K]>) => void;
14
17
  };
@@ -55,7 +58,7 @@ export declare function replayFixtureMessages(handle: MockS2sHandle, messages: R
55
58
  export declare function createFixtureSession(agent: AgentDef<any>, opts?: {
56
59
  env?: Record<string, string>;
57
60
  }): {
58
- session: import("./session.ts").Session;
61
+ session: Session;
59
62
  client: ClientSink & {
60
63
  events: unknown[];
61
64
  audioChunks: Uint8Array[];
@@ -6,10 +6,10 @@
6
6
  * Network requests go through the host's fetch proxy (with SSRF protection).
7
7
  */
8
8
  import { z } from "zod";
9
- import { type ToolSchema } from "./_internal-types.ts";
10
- import type { ToolDef } from "./types.ts";
9
+ import { type ToolSchema } from "../isolate/_internal-types.ts";
10
+ import type { ToolDef } from "../isolate/types.ts";
11
+ export { memoryTools } from "../isolate/memory-tools.ts";
11
12
  export { executeInIsolate } from "./_run-code.ts";
12
- export { memoryTools } from "./memory-tools.ts";
13
13
  /** Options for creating built-in tool definitions. */
14
14
  export type BuiltinToolOptions = {
15
15
  /** Override fetch implementation (defaults to globalThis.fetch). For testing. */