@alexkroman1/aai 0.10.3 → 0.11.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/_internal-types.d.ts +8 -1
- package/dist/_run-code.d.ts +16 -12
- package/dist/_runtime-conformance.d.ts +55 -0
- package/dist/_test-utils.d.ts +73 -0
- package/dist/_utils.d.ts +0 -19
- package/dist/_utils.js +28 -2
- package/dist/builtin-tools.d.ts +1 -5
- package/dist/constants-CwotjpJR.js +45 -0
- package/dist/constants.d.ts +42 -0
- package/dist/direct-executor-DAGCZOAN.js +1530 -0
- package/dist/direct-executor.d.ts +90 -31
- package/dist/hooks.d.ts +44 -0
- package/dist/hooks.js +58 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +19 -0
- package/dist/internal.js +164 -0
- package/dist/kv.d.ts +1 -1
- package/dist/kv.js +32 -1
- package/dist/matchers.js +1 -1
- package/dist/protocol.d.ts +3 -29
- package/dist/protocol.js +140 -2
- package/dist/server.d.ts +27 -40
- package/dist/server.js +117 -145
- package/dist/session.d.ts +65 -44
- package/dist/{testing-BbitshLb.js → testing-Dmx-dudh.js} +39 -43
- package/dist/testing.d.ts +9 -14
- package/dist/testing.js +2 -2
- package/dist/types.d.ts +24 -226
- package/dist/types.js +176 -2
- package/dist/types.test-d.d.ts +7 -0
- package/dist/vite-plugin.d.ts +15 -0
- package/dist/vite-plugin.js +82 -0
- package/dist/ws-handler.d.ts +1 -2
- package/package.json +34 -95
- package/dist/_embeddings.d.ts +0 -31
- package/dist/_internal-types-IfPcaJd5.js +0 -61
- package/dist/_internal-types.js +0 -2
- package/dist/_session-ctx.d.ts +0 -73
- package/dist/_session-otel.d.ts +0 -43
- package/dist/_session-persist.d.ts +0 -30
- package/dist/_ssrf-DCp_27V4.js +0 -123
- package/dist/_ssrf.d.ts +0 -30
- package/dist/_ssrf.js +0 -2
- package/dist/_utils-DgzpOMSV.js +0 -61
- package/dist/direct-executor-B-5mq3cu.js +0 -570
- package/dist/kv-iXtikQmR.js +0 -32
- package/dist/middleware-core-BwyBIPed.js +0 -107
- package/dist/middleware-core.d.ts +0 -47
- package/dist/middleware-core.js +0 -2
- package/dist/middleware.d.ts +0 -37
- package/dist/protocol-B-H2Q4ox.js +0 -162
- package/dist/runtime-CxcwaK68.js +0 -58
- package/dist/runtime.js +0 -2
- package/dist/s2s-M7JqtgFw.js +0 -272
- package/dist/s2s.js +0 -2
- package/dist/session-BYlwcrya.js +0 -683
- package/dist/session.js +0 -2
- package/dist/telemetry-CJlaDFNc.js +0 -95
- package/dist/telemetry.d.ts +0 -49
- package/dist/telemetry.js +0 -2
- package/dist/types-D8ZBxTL_.js +0 -192
- package/dist/unstorage-kv-CDgP-frt.js +0 -64
- package/dist/unstorage-kv.js +0 -2
- package/dist/unstorage-vector-Cj5llNhg.js +0 -172
- package/dist/unstorage-vector.d.ts +0 -47
- package/dist/unstorage-vector.js +0 -2
- package/dist/vector.d.ts +0 -86
- package/dist/vector.js +0 -49
- package/dist/worker-entry-2jaiqIj0.js +0 -70
- package/dist/worker-entry.d.ts +0 -47
- package/dist/worker-entry.js +0 -2
- package/dist/ws-handler-C0Q6eSay.js +0 -207
- package/dist/ws-handler.js +0 -2
|
@@ -1,570 +0,0 @@
|
|
|
1
|
-
import { s as defineTool } from "./types-D8ZBxTL_.js";
|
|
2
|
-
import { t as createUnstorageVectorStore } from "./unstorage-vector-Cj5llNhg.js";
|
|
3
|
-
import { a as toAgentConfig, i as agentToolsToSchemas, n as EMPTY_PARAMS } from "./_internal-types-IfPcaJd5.js";
|
|
4
|
-
import { r as ssrfSafeFetch } from "./_ssrf-DCp_27V4.js";
|
|
5
|
-
import { o as isReadOnlyFsOp, r as errorMessage, s as toolError, t as createSessionStateMap } from "./_utils-DgzpOMSV.js";
|
|
6
|
-
import { a as runOutputFilters, i as runInputFilters, n as runAfterTurnMiddleware, o as runToolCallInterceptors, r as runBeforeTurnMiddleware, t as runAfterToolCallMiddleware } from "./middleware-core-BwyBIPed.js";
|
|
7
|
-
import { n as consoleLogger, t as DEFAULT_S2S_CONFIG } from "./runtime-CxcwaK68.js";
|
|
8
|
-
import { n as createS2sSession } from "./session-BYlwcrya.js";
|
|
9
|
-
import { t as createUnstorageKv } from "./unstorage-kv-CDgP-frt.js";
|
|
10
|
-
import { t as executeToolCall } from "./worker-entry-2jaiqIj0.js";
|
|
11
|
-
import { z } from "zod";
|
|
12
|
-
import { createStorage } from "unstorage";
|
|
13
|
-
//#region _run-code.ts
|
|
14
|
-
/**
|
|
15
|
-
* run_code built-in tool — executes user JavaScript in a fresh secure-exec
|
|
16
|
-
* V8 isolate with no network, filesystem writes, or env access.
|
|
17
|
-
*/
|
|
18
|
-
const runCodeParams = z.object({ code: z.string().describe("JavaScript code to execute. Use console.log() for output.") });
|
|
19
|
-
/** Timeout for sandboxed code execution. */
|
|
20
|
-
const RUN_CODE_TIMEOUT = 5e3;
|
|
21
|
-
/** Memory limit for run_code isolates (MB). */
|
|
22
|
-
const RUN_CODE_MEMORY_MB = 32;
|
|
23
|
-
/**
|
|
24
|
-
* Execute JavaScript code inside a fresh secure-exec V8 isolate.
|
|
25
|
-
*
|
|
26
|
-
* Each invocation spins up a disposable isolate with:
|
|
27
|
-
* - No filesystem writes
|
|
28
|
-
* - No network access
|
|
29
|
-
* - No child process spawning
|
|
30
|
-
* - No environment variable access
|
|
31
|
-
* - 32 MB memory limit
|
|
32
|
-
* - 5 second execution timeout
|
|
33
|
-
*
|
|
34
|
-
* The isolate is disposed immediately after execution, so no state
|
|
35
|
-
* leaks between invocations or across sessions.
|
|
36
|
-
*/
|
|
37
|
-
function createRunCode() {
|
|
38
|
-
return {
|
|
39
|
-
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.",
|
|
40
|
-
parameters: runCodeParams,
|
|
41
|
-
async execute(args) {
|
|
42
|
-
return executeInIsolate(args.code);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/** Lazily import secure-exec to avoid top-level side effects. */
|
|
47
|
-
let _secureExecPromise;
|
|
48
|
-
function getSecureExec() {
|
|
49
|
-
_secureExecPromise ??= import("secure-exec");
|
|
50
|
-
return _secureExecPromise;
|
|
51
|
-
}
|
|
52
|
-
const RUN_CODE_HARNESS = `
|
|
53
|
-
import { readFileSync } from "node:fs";
|
|
54
|
-
|
|
55
|
-
const __output = [];
|
|
56
|
-
const __capture = (...args) => __output.push(args.map(String).join(" "));
|
|
57
|
-
const __console = {
|
|
58
|
-
log: __capture, info: __capture, warn: __capture,
|
|
59
|
-
error: __capture, debug: __capture,
|
|
60
|
-
};
|
|
61
|
-
try {
|
|
62
|
-
const __userCode = readFileSync("/app/user-code.js", "utf8");
|
|
63
|
-
const __AsyncFn = Object.getPrototypeOf(async function(){}).constructor;
|
|
64
|
-
const __fn = new __AsyncFn("console", __userCode);
|
|
65
|
-
await __fn(__console);
|
|
66
|
-
const result = __output.join("\\n").trim();
|
|
67
|
-
process.stdout.write(JSON.stringify({ ok: true, result: result || "Code ran successfully (no output)" }));
|
|
68
|
-
} catch (err) {
|
|
69
|
-
process.stdout.write(JSON.stringify({ ok: false, error: String(err?.message ?? err) }));
|
|
70
|
-
}
|
|
71
|
-
`;
|
|
72
|
-
const IsolateOutputSchema = z.object({
|
|
73
|
-
ok: z.boolean(),
|
|
74
|
-
result: z.string().optional(),
|
|
75
|
-
error: z.string().optional()
|
|
76
|
-
});
|
|
77
|
-
/** Parse stdout from the run_code harness into a result or error. */
|
|
78
|
-
function parseIsolateOutput(stdout, stderr) {
|
|
79
|
-
if (!stdout) {
|
|
80
|
-
if (stderr) return { error: stderr.trim() };
|
|
81
|
-
return { error: "Code execution timed out" };
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
const parsed = IsolateOutputSchema.parse(JSON.parse(stdout));
|
|
85
|
-
if (parsed.ok) return parsed.result ?? "Code ran successfully (no output)";
|
|
86
|
-
return { error: parsed.error ?? "Unknown error" };
|
|
87
|
-
} catch {
|
|
88
|
-
return stdout.trim() || "Code ran successfully (no output)";
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Exported for testing — execute user code in a fresh secure-exec V8 isolate.
|
|
93
|
-
*/
|
|
94
|
-
async function executeInIsolate(code) {
|
|
95
|
-
const { createInMemoryFileSystem, createNodeDriver, createNodeRuntimeDriverFactory, NodeRuntime } = await getSecureExec();
|
|
96
|
-
const fs = createInMemoryFileSystem();
|
|
97
|
-
await fs.writeFile("/app/harness.js", RUN_CODE_HARNESS);
|
|
98
|
-
await fs.writeFile("/app/user-code.js", code);
|
|
99
|
-
const stdoutChunks = [];
|
|
100
|
-
const stderrChunks = [];
|
|
101
|
-
let resolveOutput = null;
|
|
102
|
-
const outputReady = new Promise((r) => {
|
|
103
|
-
resolveOutput = r;
|
|
104
|
-
});
|
|
105
|
-
const runtime = new NodeRuntime({
|
|
106
|
-
systemDriver: createNodeDriver({
|
|
107
|
-
filesystem: fs,
|
|
108
|
-
permissions: {
|
|
109
|
-
fs: (req) => isReadOnlyFsOp(req.op) ? { allow: true } : {
|
|
110
|
-
allow: false,
|
|
111
|
-
reason: "Filesystem is read-only"
|
|
112
|
-
},
|
|
113
|
-
network: () => ({
|
|
114
|
-
allow: false,
|
|
115
|
-
reason: "Network access is disabled in run_code"
|
|
116
|
-
}),
|
|
117
|
-
childProcess: () => ({
|
|
118
|
-
allow: false,
|
|
119
|
-
reason: "Subprocess spawning is disabled"
|
|
120
|
-
}),
|
|
121
|
-
env: () => ({
|
|
122
|
-
allow: false,
|
|
123
|
-
reason: "Env access is disabled in run_code"
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
}),
|
|
127
|
-
runtimeDriverFactory: createNodeRuntimeDriverFactory(),
|
|
128
|
-
memoryLimit: RUN_CODE_MEMORY_MB,
|
|
129
|
-
onStdio(event) {
|
|
130
|
-
if (event.channel === "stdout") stdoutChunks.push(event.message);
|
|
131
|
-
if (event.channel === "stderr") stderrChunks.push(event.message);
|
|
132
|
-
resolveOutput?.();
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
const execPromise = runtime.exec("import \"/app/harness.js\";", { cwd: "/app" });
|
|
136
|
-
try {
|
|
137
|
-
await Promise.race([outputReady, new Promise((r) => setTimeout(r, RUN_CODE_TIMEOUT))]);
|
|
138
|
-
await Promise.race([execPromise.catch(() => {}), new Promise((r) => setTimeout(r, 200))]);
|
|
139
|
-
return parseIsolateOutput(stdoutChunks.join(""), stderrChunks.join(""));
|
|
140
|
-
} catch (err) {
|
|
141
|
-
return { error: errorMessage(err) };
|
|
142
|
-
} finally {
|
|
143
|
-
runtime.dispose();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region memory-tools.ts
|
|
148
|
-
/**
|
|
149
|
-
* KV-backed memory tools for agent persistent state.
|
|
150
|
-
*/
|
|
151
|
-
/**
|
|
152
|
-
* Returns a standard set of KV-backed memory tools: `save_memory`,
|
|
153
|
-
* `recall_memory`, `list_memories`, and `forget_memory`.
|
|
154
|
-
*
|
|
155
|
-
* Spread the result into your agent's `tools` record.
|
|
156
|
-
*
|
|
157
|
-
* @example
|
|
158
|
-
* ```ts
|
|
159
|
-
* import { defineAgent, memoryTools } from "aai";
|
|
160
|
-
*
|
|
161
|
-
* export default defineAgent({
|
|
162
|
-
* name: "My Agent",
|
|
163
|
-
* tools: { ...memoryTools() },
|
|
164
|
-
* });
|
|
165
|
-
* ```
|
|
166
|
-
*
|
|
167
|
-
* @returns A record with four tool definitions: `save_memory`, `recall_memory`,
|
|
168
|
-
* `list_memories`, and `forget_memory`.
|
|
169
|
-
* @public
|
|
170
|
-
*/
|
|
171
|
-
function memoryTools() {
|
|
172
|
-
return {
|
|
173
|
-
save_memory: defineTool({
|
|
174
|
-
description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
|
|
175
|
-
parameters: z.object({
|
|
176
|
-
key: z.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
|
|
177
|
-
value: z.string().describe("The information to remember")
|
|
178
|
-
}),
|
|
179
|
-
execute: async ({ key, value }, ctx) => {
|
|
180
|
-
await ctx.kv.set(key, value);
|
|
181
|
-
return { saved: key };
|
|
182
|
-
}
|
|
183
|
-
}),
|
|
184
|
-
recall_memory: defineTool({
|
|
185
|
-
description: "Retrieve a previously saved memory by its key.",
|
|
186
|
-
parameters: z.object({ key: z.string().describe("The key to look up") }),
|
|
187
|
-
execute: async ({ key }, ctx) => {
|
|
188
|
-
const value = await ctx.kv.get(key);
|
|
189
|
-
if (value === null) return {
|
|
190
|
-
found: false,
|
|
191
|
-
key
|
|
192
|
-
};
|
|
193
|
-
return {
|
|
194
|
-
found: true,
|
|
195
|
-
key,
|
|
196
|
-
value
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
}),
|
|
200
|
-
list_memories: defineTool({
|
|
201
|
-
description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
|
|
202
|
-
parameters: z.object({ prefix: z.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional() }),
|
|
203
|
-
execute: async ({ prefix }, ctx) => {
|
|
204
|
-
const entries = await ctx.kv.list(prefix ?? "");
|
|
205
|
-
return {
|
|
206
|
-
count: entries.length,
|
|
207
|
-
keys: entries.map((e) => e.key)
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
}),
|
|
211
|
-
forget_memory: defineTool({
|
|
212
|
-
description: "Delete a previously saved memory by its key.",
|
|
213
|
-
parameters: z.object({ key: z.string().describe("The key to delete") }),
|
|
214
|
-
execute: async ({ key }, ctx) => {
|
|
215
|
-
await ctx.kv.delete(key);
|
|
216
|
-
return { deleted: key };
|
|
217
|
-
}
|
|
218
|
-
})
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
//#endregion
|
|
222
|
-
//#region builtin-tools.ts
|
|
223
|
-
/**
|
|
224
|
-
* Built-in tool definitions for the AAI agent SDK.
|
|
225
|
-
*
|
|
226
|
-
* In self-hosted mode, these run in-process alongside custom tools.
|
|
227
|
-
* In platform mode, they run on the host process outside the sandbox.
|
|
228
|
-
* Network requests go through the host's fetch proxy (with SSRF protection).
|
|
229
|
-
*/
|
|
230
|
-
/** Per-fetch timeout for network tools — tighter than the overall tool timeout. */
|
|
231
|
-
const FETCH_TIMEOUT_MS = 15e3;
|
|
232
|
-
const fetchSignal = () => AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
233
|
-
/** Lazily import html-to-text to avoid loading 824KB dep tree at startup. */
|
|
234
|
-
let _htmlToTextPromise;
|
|
235
|
-
function getHtmlToText() {
|
|
236
|
-
_htmlToTextPromise ??= import("html-to-text");
|
|
237
|
-
return _htmlToTextPromise;
|
|
238
|
-
}
|
|
239
|
-
async function htmlToText(html) {
|
|
240
|
-
const { convert } = await getHtmlToText();
|
|
241
|
-
return convert(html, { wordwrap: false });
|
|
242
|
-
}
|
|
243
|
-
const webSearchParams = z.object({
|
|
244
|
-
query: z.string().describe("The search query"),
|
|
245
|
-
max_results: z.number().describe("Maximum number of results to return (default 5)").optional()
|
|
246
|
-
});
|
|
247
|
-
const BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
248
|
-
const BraveSearchResponseSchema = z.object({ web: z.object({ results: z.array(z.object({
|
|
249
|
-
title: z.string(),
|
|
250
|
-
url: z.string(),
|
|
251
|
-
description: z.string()
|
|
252
|
-
})) }).optional() });
|
|
253
|
-
function createWebSearch(fetchFn = globalThis.fetch) {
|
|
254
|
-
return {
|
|
255
|
-
description: "Search the web for current information, facts, news, or answers to questions. Returns a list of results with title, URL, and description. Use this when the user asks about something you don't know, need up-to-date information, or want to verify facts.",
|
|
256
|
-
parameters: webSearchParams,
|
|
257
|
-
async execute(args, ctx) {
|
|
258
|
-
const { query, max_results: maxResults = 5 } = args;
|
|
259
|
-
const apiKey = ctx.env.BRAVE_API_KEY ?? "";
|
|
260
|
-
if (!apiKey) return { error: "BRAVE_API_KEY is not set — web search unavailable" };
|
|
261
|
-
const resp = await fetchFn(`${BRAVE_SEARCH_URL}?${new URLSearchParams({
|
|
262
|
-
q: query,
|
|
263
|
-
count: String(maxResults),
|
|
264
|
-
text_decorations: "false"
|
|
265
|
-
})}`, {
|
|
266
|
-
headers: { "X-Subscription-Token": apiKey },
|
|
267
|
-
signal: fetchSignal()
|
|
268
|
-
});
|
|
269
|
-
if (!resp.ok) return { error: `Search request failed: ${resp.status} ${resp.statusText}` };
|
|
270
|
-
const raw = await resp.json();
|
|
271
|
-
const data = BraveSearchResponseSchema.safeParse(raw);
|
|
272
|
-
if (!data.success) return { error: "Unexpected search response format" };
|
|
273
|
-
return (data.data.web?.results ?? []).slice(0, maxResults).map((r) => ({
|
|
274
|
-
title: r.title,
|
|
275
|
-
url: r.url,
|
|
276
|
-
description: r.description
|
|
277
|
-
}));
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
const MAX_PAGE_CHARS = 1e4;
|
|
282
|
-
const MAX_HTML_BYTES = 2e5;
|
|
283
|
-
const visitWebpageParams = z.object({ url: z.string().describe("The full URL to fetch (e.g., 'https://example.com/page')") });
|
|
284
|
-
function createVisitWebpage(fetchFn = globalThis.fetch) {
|
|
285
|
-
return {
|
|
286
|
-
description: "Fetch a webpage and return its content as clean text. Use this to read the full content of a URL found via web_search, or any link the user shares. Good for reading articles, documentation, blog posts, or product pages.",
|
|
287
|
-
parameters: visitWebpageParams,
|
|
288
|
-
async execute(args, _ctx) {
|
|
289
|
-
const { url } = args;
|
|
290
|
-
const resp = await ssrfSafeFetch(url, {
|
|
291
|
-
headers: {
|
|
292
|
-
"User-Agent": "Mozilla/5.0 (compatible; VoiceAgent/1.0; +https://github.com/AssemblyAI/aai)",
|
|
293
|
-
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
294
|
-
},
|
|
295
|
-
signal: fetchSignal()
|
|
296
|
-
}, fetchFn);
|
|
297
|
-
if (!resp.ok) return {
|
|
298
|
-
error: `Failed to fetch: ${resp.status} ${resp.statusText}`,
|
|
299
|
-
url
|
|
300
|
-
};
|
|
301
|
-
const htmlContent = await resp.text();
|
|
302
|
-
const text = await htmlToText(htmlContent.length > MAX_HTML_BYTES ? htmlContent.slice(0, MAX_HTML_BYTES) : htmlContent);
|
|
303
|
-
const truncated = text.length > MAX_PAGE_CHARS;
|
|
304
|
-
return {
|
|
305
|
-
url,
|
|
306
|
-
content: truncated ? text.slice(0, MAX_PAGE_CHARS) : text,
|
|
307
|
-
...truncated ? {
|
|
308
|
-
truncated: true,
|
|
309
|
-
totalChars: text.length
|
|
310
|
-
} : {}
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
const fetchJsonParams = z.object({
|
|
316
|
-
url: z.string().describe("The URL to fetch JSON from"),
|
|
317
|
-
headers: z.record(z.string(), z.string()).describe("Optional HTTP headers to include in the request (only safe headers like Accept, Content-Type are allowed)").optional()
|
|
318
|
-
});
|
|
319
|
-
/** Headers the LLM must never control — could exfiltrate credentials or manipulate routing. */
|
|
320
|
-
const BLOCKED_FETCH_HEADERS = new Set([
|
|
321
|
-
"authorization",
|
|
322
|
-
"cookie",
|
|
323
|
-
"set-cookie",
|
|
324
|
-
"host",
|
|
325
|
-
"proxy-authorization",
|
|
326
|
-
"x-forwarded-for",
|
|
327
|
-
"x-forwarded-host",
|
|
328
|
-
"x-forwarded-proto",
|
|
329
|
-
"x-real-ip",
|
|
330
|
-
"cf-connecting-ip",
|
|
331
|
-
"fly-client-ip"
|
|
332
|
-
]);
|
|
333
|
-
function sanitizeHeaders(raw) {
|
|
334
|
-
if (!raw) return;
|
|
335
|
-
const safe = {};
|
|
336
|
-
for (const [key, value] of Object.entries(raw)) if (!BLOCKED_FETCH_HEADERS.has(key.toLowerCase())) safe[key] = value;
|
|
337
|
-
return Object.keys(safe).length > 0 ? safe : void 0;
|
|
338
|
-
}
|
|
339
|
-
function createFetchJson(fetchFn = globalThis.fetch) {
|
|
340
|
-
return {
|
|
341
|
-
description: "Call a REST API endpoint via HTTP GET and return the JSON response. Use this to fetch structured data from APIs — for example, weather data, stock prices, exchange rates, or any public JSON API. Supports custom headers for authenticated APIs.",
|
|
342
|
-
parameters: fetchJsonParams,
|
|
343
|
-
async execute(args, _ctx) {
|
|
344
|
-
const { url, headers } = args;
|
|
345
|
-
const safeHeaders = sanitizeHeaders(headers);
|
|
346
|
-
const resp = await ssrfSafeFetch(url, {
|
|
347
|
-
...safeHeaders && { headers: safeHeaders },
|
|
348
|
-
signal: fetchSignal()
|
|
349
|
-
}, fetchFn);
|
|
350
|
-
if (!resp.ok) return {
|
|
351
|
-
error: `HTTP ${resp.status} ${resp.statusText}`,
|
|
352
|
-
url
|
|
353
|
-
};
|
|
354
|
-
try {
|
|
355
|
-
return await resp.json();
|
|
356
|
-
} catch {
|
|
357
|
-
return {
|
|
358
|
-
error: "Response was not valid JSON",
|
|
359
|
-
url
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
const vectorSearchParams = z.object({
|
|
366
|
-
query: z.string().describe("Short keyword query to search the knowledge base. Use specific topic terms, not full sentences. Do NOT include the company or product name since all documents are from the same source. For example, if the user asks \"how much does Acme cost\", search for \"pricing plans rates\"."),
|
|
367
|
-
topK: z.number().describe("Maximum results to return (default: 5)").optional()
|
|
368
|
-
});
|
|
369
|
-
function createVectorSearch(vectorSearchFn) {
|
|
370
|
-
return {
|
|
371
|
-
description: "Search the agent's knowledge base for relevant information. Use this when the user asks a question that might be answered by previously ingested documents or data. Returns the most relevant matches ranked by similarity.",
|
|
372
|
-
parameters: vectorSearchParams,
|
|
373
|
-
async execute(args) {
|
|
374
|
-
const { query, topK = 5 } = args;
|
|
375
|
-
return vectorSearchFn(query, topK);
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
/** Resolve a builtin name to an array of [toolName, ToolDef] pairs. */
|
|
380
|
-
function resolveBuiltin(name, opts) {
|
|
381
|
-
switch (name) {
|
|
382
|
-
case "web_search": return [["web_search", createWebSearch(opts?.fetch)]];
|
|
383
|
-
case "visit_webpage": return [["visit_webpage", createVisitWebpage(opts?.fetch)]];
|
|
384
|
-
case "fetch_json": return [["fetch_json", createFetchJson(opts?.fetch)]];
|
|
385
|
-
case "run_code": return [["run_code", createRunCode()]];
|
|
386
|
-
case "vector_search":
|
|
387
|
-
if (!opts?.vectorSearch) return [];
|
|
388
|
-
return [["vector_search", createVectorSearch(opts.vectorSearch)]];
|
|
389
|
-
case "memory": return Object.entries(memoryTools());
|
|
390
|
-
default: return [];
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Create built-in tool definitions for the given tool names.
|
|
395
|
-
* For runtime use — vector_search requires opts.vectorSearch to be included.
|
|
396
|
-
*/
|
|
397
|
-
function getBuiltinToolDefs(names, opts) {
|
|
398
|
-
const defs = {};
|
|
399
|
-
for (const name of names) for (const [k, v] of resolveBuiltin(name, opts)) defs[k] = v;
|
|
400
|
-
return defs;
|
|
401
|
-
}
|
|
402
|
-
/** Returns JSON tool schemas for the specified builtin tools. */
|
|
403
|
-
function getBuiltinToolSchemas(names) {
|
|
404
|
-
return names.flatMap((name) => resolveBuiltin(name, { vectorSearch: async () => "" }).map(([toolName, def]) => ({
|
|
405
|
-
name: toolName,
|
|
406
|
-
description: def.description,
|
|
407
|
-
parameters: z.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
408
|
-
})));
|
|
409
|
-
}
|
|
410
|
-
//#endregion
|
|
411
|
-
//#region direct-executor.ts
|
|
412
|
-
/**
|
|
413
|
-
* Direct tool execution for self-hosted mode.
|
|
414
|
-
*
|
|
415
|
-
* In self-hosted mode, agent code is trusted (you're running your own code).
|
|
416
|
-
* Tools execute directly in-process — no sandbox, no RPC.
|
|
417
|
-
*/
|
|
418
|
-
/** Create an in-memory KV store (default for self-hosted). */
|
|
419
|
-
function createLocalKv() {
|
|
420
|
-
return createUnstorageKv({ storage: createStorage() });
|
|
421
|
-
}
|
|
422
|
-
/** Create an in-memory vector store (default for self-hosted). */
|
|
423
|
-
function createLocalVectorStore() {
|
|
424
|
-
return createUnstorageVectorStore({ storage: createStorage() });
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Create a direct (in-process) tool executor and hook invoker for an agent.
|
|
428
|
-
*
|
|
429
|
-
* Merges built-in and custom tool definitions, builds tool schemas for the
|
|
430
|
-
* S2S API, and wires up middleware and lifecycle hooks.
|
|
431
|
-
*
|
|
432
|
-
* @param opts - Executor configuration. See {@link DirectExecutorOptions}.
|
|
433
|
-
* @returns A {@link DirectExecutor} with tool execution, hook invocation,
|
|
434
|
-
* schemas, and session creation.
|
|
435
|
-
*/
|
|
436
|
-
function createDirectExecutor(opts) {
|
|
437
|
-
const { agent, env, kv = createLocalKv(), vector = createLocalVectorStore(), vectorSearch, createWebSocket, logger = consoleLogger, s2sConfig = DEFAULT_S2S_CONFIG } = opts;
|
|
438
|
-
const agentConfig = toAgentConfig(agent);
|
|
439
|
-
const allTools = {
|
|
440
|
-
...getBuiltinToolDefs(agent.builtinTools ?? [], vectorSearch ? { vectorSearch } : void 0),
|
|
441
|
-
...agent.tools
|
|
442
|
-
};
|
|
443
|
-
const customSchemas = agentToolsToSchemas(agent.tools ?? {});
|
|
444
|
-
const builtinSchemas = getBuiltinToolSchemas(agent.builtinTools ?? []);
|
|
445
|
-
const toolSchemas = [...customSchemas, ...builtinSchemas];
|
|
446
|
-
const sessionState = createSessionStateMap(agent.state);
|
|
447
|
-
const frozenEnv = Object.freeze({ ...env });
|
|
448
|
-
/** SSRF-safe fetch for tool/hook contexts in self-hosted mode. */
|
|
449
|
-
const safeFetch = (input, init) => {
|
|
450
|
-
const req = new Request(input, init);
|
|
451
|
-
return ssrfSafeFetch(req.url, {
|
|
452
|
-
...init,
|
|
453
|
-
method: req.method
|
|
454
|
-
}, globalThis.fetch);
|
|
455
|
-
};
|
|
456
|
-
function makeHookContext(sessionId) {
|
|
457
|
-
return {
|
|
458
|
-
env: frozenEnv,
|
|
459
|
-
state: sessionState.get(sessionId),
|
|
460
|
-
sessionId,
|
|
461
|
-
get kv() {
|
|
462
|
-
return kv;
|
|
463
|
-
},
|
|
464
|
-
get vector() {
|
|
465
|
-
return vector;
|
|
466
|
-
},
|
|
467
|
-
fetch: safeFetch
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
const executeTool = async (name, args, sessionId, messages, onUpdate) => {
|
|
471
|
-
const tool = allTools[name];
|
|
472
|
-
if (!tool) return toolError(`Unknown tool: ${name}`);
|
|
473
|
-
return executeToolCall(name, args, {
|
|
474
|
-
tool,
|
|
475
|
-
env: frozenEnv,
|
|
476
|
-
state: sessionState.get(sessionId ?? ""),
|
|
477
|
-
sessionId: sessionId ?? "",
|
|
478
|
-
kv,
|
|
479
|
-
vector,
|
|
480
|
-
messages,
|
|
481
|
-
logger,
|
|
482
|
-
onUpdate,
|
|
483
|
-
fetch: safeFetch
|
|
484
|
-
});
|
|
485
|
-
};
|
|
486
|
-
const middleware = agent.middleware ?? [];
|
|
487
|
-
const hookInvoker = {
|
|
488
|
-
async onConnect(sessionId) {
|
|
489
|
-
await agent.onConnect?.(makeHookContext(sessionId));
|
|
490
|
-
},
|
|
491
|
-
async onDisconnect(sessionId) {
|
|
492
|
-
await agent.onDisconnect?.(makeHookContext(sessionId));
|
|
493
|
-
sessionState.delete(sessionId);
|
|
494
|
-
},
|
|
495
|
-
async onTurn(sessionId, text) {
|
|
496
|
-
await agent.onTurn?.(text, makeHookContext(sessionId));
|
|
497
|
-
},
|
|
498
|
-
async onError(sessionId, error) {
|
|
499
|
-
await agent.onError?.(new Error(error.message), makeHookContext(sessionId));
|
|
500
|
-
},
|
|
501
|
-
async onStep(sessionId, step) {
|
|
502
|
-
await agent.onStep?.(step, makeHookContext(sessionId));
|
|
503
|
-
},
|
|
504
|
-
async resolveTurnConfig(sessionId) {
|
|
505
|
-
const ctx = makeHookContext(sessionId);
|
|
506
|
-
const maxSteps = typeof agent.maxSteps === "function" ? await agent.maxSteps(ctx) ?? void 0 : void 0;
|
|
507
|
-
if (maxSteps === void 0) return null;
|
|
508
|
-
return { maxSteps };
|
|
509
|
-
},
|
|
510
|
-
async filterInput(sessionId, text) {
|
|
511
|
-
if (middleware.length === 0) return text;
|
|
512
|
-
return runInputFilters(middleware, text, makeHookContext(sessionId));
|
|
513
|
-
},
|
|
514
|
-
async beforeTurn(sessionId, text) {
|
|
515
|
-
if (middleware.length === 0) return;
|
|
516
|
-
return (await runBeforeTurnMiddleware(middleware, text, makeHookContext(sessionId)))?.reason;
|
|
517
|
-
},
|
|
518
|
-
async afterTurn(sessionId, text) {
|
|
519
|
-
if (middleware.length === 0) return;
|
|
520
|
-
await runAfterTurnMiddleware(middleware, text, makeHookContext(sessionId));
|
|
521
|
-
},
|
|
522
|
-
async interceptToolCall(sessionId, toolName, args) {
|
|
523
|
-
if (middleware.length === 0) return;
|
|
524
|
-
return runToolCallInterceptors(middleware, toolName, args, makeHookContext(sessionId));
|
|
525
|
-
},
|
|
526
|
-
async afterToolCall(sessionId, toolName, args, result) {
|
|
527
|
-
if (middleware.length === 0) return;
|
|
528
|
-
await runAfterToolCallMiddleware(middleware, toolName, args, result, makeHookContext(sessionId));
|
|
529
|
-
},
|
|
530
|
-
async filterOutput(sessionId, text) {
|
|
531
|
-
if (middleware.length === 0) return text;
|
|
532
|
-
return runOutputFilters(middleware, text, makeHookContext(sessionId));
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
function createSession(sessionOpts) {
|
|
536
|
-
const apiKey = frozenEnv.ASSEMBLYAI_API_KEY ?? "";
|
|
537
|
-
const persistenceOpts = agent.persistence ? {
|
|
538
|
-
persistence: {
|
|
539
|
-
kv,
|
|
540
|
-
ttl: agent.persistence.ttl,
|
|
541
|
-
getState: () => sessionState.get(sessionOpts.id),
|
|
542
|
-
setState: (state) => sessionState.set(sessionOpts.id, state)
|
|
543
|
-
},
|
|
544
|
-
...sessionOpts.resumeFrom ? { resumeFrom: sessionOpts.resumeFrom } : {}
|
|
545
|
-
} : {};
|
|
546
|
-
return createS2sSession({
|
|
547
|
-
id: sessionOpts.id,
|
|
548
|
-
agent: sessionOpts.agent,
|
|
549
|
-
client: sessionOpts.client,
|
|
550
|
-
agentConfig,
|
|
551
|
-
toolSchemas,
|
|
552
|
-
apiKey,
|
|
553
|
-
s2sConfig,
|
|
554
|
-
executeTool,
|
|
555
|
-
...createWebSocket ? { createWebSocket } : {},
|
|
556
|
-
hookInvoker,
|
|
557
|
-
skipGreeting: sessionOpts.skipGreeting ?? false,
|
|
558
|
-
logger,
|
|
559
|
-
...persistenceOpts
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
return {
|
|
563
|
-
executeTool,
|
|
564
|
-
hookInvoker,
|
|
565
|
-
toolSchemas,
|
|
566
|
-
createSession
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
//#endregion
|
|
570
|
-
export { createDirectExecutor as t };
|
package/dist/kv-iXtikQmR.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
//#region kv.ts
|
|
2
|
-
const MAX_VALUE_SIZE = 65536;
|
|
3
|
-
/** Sort entries by key and apply reverse/limit options. Mutates the array. */
|
|
4
|
-
function sortAndPaginate(entries, options) {
|
|
5
|
-
entries.sort((a, b) => a.key.localeCompare(b.key));
|
|
6
|
-
if (options?.reverse) entries.reverse();
|
|
7
|
-
if (options?.limit && options.limit > 0) entries.length = Math.min(entries.length, options.limit);
|
|
8
|
-
return entries;
|
|
9
|
-
}
|
|
10
|
-
/** Maximum allowed glob pattern length to prevent ReDoS. */
|
|
11
|
-
const MAX_GLOB_PATTERN_LENGTH = 1024;
|
|
12
|
-
/** Simple glob matcher — supports `*` as a wildcard for any characters. */
|
|
13
|
-
function matchGlob(key, pattern) {
|
|
14
|
-
if (pattern.length > MAX_GLOB_PATTERN_LENGTH) throw new Error(`Glob pattern exceeds maximum length of ${MAX_GLOB_PATTERN_LENGTH}`);
|
|
15
|
-
const parts = pattern.split("*");
|
|
16
|
-
if (parts.length === 1) return key === pattern;
|
|
17
|
-
const first = parts[0];
|
|
18
|
-
if (!key.startsWith(first)) return false;
|
|
19
|
-
const last = parts.at(-1);
|
|
20
|
-
if (key.length < first.length + last.length) return false;
|
|
21
|
-
if (!key.endsWith(last)) return false;
|
|
22
|
-
let pos = first.length;
|
|
23
|
-
const end = key.length - last.length;
|
|
24
|
-
for (const part of parts.slice(1, -1)) {
|
|
25
|
-
const idx = key.indexOf(part, pos);
|
|
26
|
-
if (idx === -1 || idx > end) return false;
|
|
27
|
-
pos = idx + part.length;
|
|
28
|
-
}
|
|
29
|
-
return pos <= end;
|
|
30
|
-
}
|
|
31
|
-
//#endregion
|
|
32
|
-
export { matchGlob as n, sortAndPaginate as r, MAX_VALUE_SIZE as t };
|