@alexkroman1/aai 0.9.3 → 0.10.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.
- package/dist/_internal-types.d.ts +49 -22
- package/dist/_internal-types.js +43 -1
- package/dist/_mock-ws.d.ts +1 -2
- package/dist/_run-code.d.ts +31 -0
- package/dist/_session-ctx.d.ts +73 -0
- package/dist/_session-otel.d.ts +43 -0
- package/dist/_session-persist.d.ts +30 -0
- package/dist/_ssrf.d.ts +30 -0
- package/dist/_ssrf.js +123 -0
- package/dist/_utils.d.ts +25 -0
- package/dist/_utils.js +54 -1
- package/dist/builtin-tools.d.ts +5 -34
- package/dist/direct-executor-Ca0wt5H0.js +572 -0
- package/dist/direct-executor.d.ts +34 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/kv.d.ts +30 -38
- package/dist/kv.js +19 -86
- package/dist/matchers.d.ts +20 -0
- package/dist/matchers.js +41 -0
- package/dist/memory-tools.d.ts +39 -0
- package/dist/middleware-core.d.ts +47 -0
- package/dist/middleware-core.js +107 -0
- package/dist/middleware.d.ts +37 -0
- package/dist/protocol.d.ts +44 -24
- package/dist/protocol.js +34 -14
- package/dist/runtime.d.ts +26 -2
- package/dist/runtime.js +44 -7
- package/dist/s2s.d.ts +19 -29
- package/dist/s2s.js +117 -87
- package/dist/server.d.ts +31 -3
- package/dist/server.js +102 -28
- package/dist/session-BkN9u0ni.js +683 -0
- package/dist/session.d.ts +55 -28
- package/dist/session.js +2 -312
- package/dist/sqlite-kv.d.ts +34 -0
- package/dist/sqlite-kv.js +133 -0
- package/dist/sqlite-vector.d.ts +58 -0
- package/dist/sqlite-vector.js +149 -0
- package/dist/system-prompt.d.ts +21 -0
- package/dist/telemetry.d.ts +49 -0
- package/dist/telemetry.js +95 -0
- package/dist/testing-MRl3SXsI.js +519 -0
- package/dist/testing.d.ts +299 -0
- package/dist/testing.js +2 -0
- package/dist/types.d.ts +324 -39
- package/dist/types.js +62 -9
- package/dist/vector.d.ts +18 -22
- package/dist/vector.js +41 -48
- package/dist/worker-entry.d.ts +11 -3
- package/dist/worker-entry.js +19 -8
- package/dist/ws-handler.d.ts +7 -3
- package/dist/ws-handler.js +64 -12
- package/package.json +55 -8
- package/dist/_mock-ws.js +0 -158
- package/dist/builtin-tools.js +0 -270
- package/dist/direct-executor.js +0 -125
package/dist/types.d.ts
CHANGED
|
@@ -5,12 +5,152 @@ import { z } from "zod";
|
|
|
5
5
|
import type { Kv } from "./kv.ts";
|
|
6
6
|
import type { VectorStore } from "./vector.ts";
|
|
7
7
|
/**
|
|
8
|
-
* Result
|
|
8
|
+
* Result returned by a `beforeTurn` middleware to block a turn.
|
|
9
9
|
* @public
|
|
10
10
|
*/
|
|
11
|
-
export type
|
|
12
|
-
|
|
11
|
+
export type MiddlewareBlockResult = {
|
|
12
|
+
block: true;
|
|
13
|
+
reason: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Result returned by a `beforeToolCall` middleware hook to short-circuit tool execution.
|
|
17
|
+
*
|
|
18
|
+
* Return `{ result: string }` to skip execution and use a cached/synthetic result.
|
|
19
|
+
* Return `{ block: true; reason: string }` to deny the tool call.
|
|
20
|
+
* Return `{ args: Record<string, unknown> }` to transform the arguments.
|
|
21
|
+
* Return `undefined` to proceed normally.
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export type ToolCallInterceptResult = {
|
|
26
|
+
result: string;
|
|
27
|
+
} | {
|
|
28
|
+
block: true;
|
|
29
|
+
reason: string;
|
|
30
|
+
} | {
|
|
31
|
+
args: Record<string, unknown>;
|
|
13
32
|
} | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Composable middleware for the agent lifecycle.
|
|
35
|
+
*
|
|
36
|
+
* Middleware can intercept turns, tool calls, and output at well-defined
|
|
37
|
+
* points. Multiple middleware compose in array order: the first middleware
|
|
38
|
+
* in the array runs first for "before" hooks and last for "after" hooks.
|
|
39
|
+
*
|
|
40
|
+
* ## Middleware Composition Order
|
|
41
|
+
*
|
|
42
|
+
* **"Before" hooks** run in array order (first middleware → last):
|
|
43
|
+
* `beforeInput` → `beforeTurn` → `beforeToolCall` → `beforeOutput`
|
|
44
|
+
*
|
|
45
|
+
* **"After" hooks** run in reverse array order (last middleware → first):
|
|
46
|
+
* `afterToolCall` → `afterTurn`
|
|
47
|
+
*
|
|
48
|
+
* ### Execution flow for a user turn
|
|
49
|
+
*
|
|
50
|
+
* ```
|
|
51
|
+
* User text arrives
|
|
52
|
+
* │
|
|
53
|
+
* ▼
|
|
54
|
+
* beforeInput — transform/redact input text (piped through each middleware)
|
|
55
|
+
* │
|
|
56
|
+
* ▼
|
|
57
|
+
* beforeTurn — block or allow the turn (short-circuits on first block)
|
|
58
|
+
* │
|
|
59
|
+
* ▼ (if not blocked)
|
|
60
|
+
* LLM reasoning + tool calls
|
|
61
|
+
* │ ┌─ beforeToolCall (per call, short-circuits on block/result)
|
|
62
|
+
* │ └─ afterToolCall (per call, reverse order)
|
|
63
|
+
* │
|
|
64
|
+
* ▼
|
|
65
|
+
* beforeOutput — transform/redact LLM output text (piped through each middleware)
|
|
66
|
+
* │
|
|
67
|
+
* ▼
|
|
68
|
+
* afterTurn — cleanup/logging (reverse order)
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* ### Short-circuit behavior
|
|
72
|
+
*
|
|
73
|
+
* - **`beforeTurn`**: If *any* middleware returns `{ block: true, reason }`,
|
|
74
|
+
* the turn is blocked and subsequent `beforeTurn` hooks do **not** run.
|
|
75
|
+
* When a turn is blocked, `afterTurn` hooks do **not** fire (the turn
|
|
76
|
+
* never started).
|
|
77
|
+
* - **`beforeToolCall`**: If *any* middleware blocks or returns a cached
|
|
78
|
+
* result, subsequent `beforeToolCall` hooks do **not** run. Arg transforms
|
|
79
|
+
* accumulate across middleware.
|
|
80
|
+
* - **`beforeInput`** / **`beforeOutput`**: These *always* run all middleware
|
|
81
|
+
* in sequence (no short-circuit). Each receives the output of the previous.
|
|
82
|
+
*
|
|
83
|
+
* ### Ordering example
|
|
84
|
+
*
|
|
85
|
+
* ```ts
|
|
86
|
+
* middleware: [auditTrail, hipaaGuardrails]
|
|
87
|
+
* ```
|
|
88
|
+
* - `beforeInput`: auditTrail runs first, then hipaaGuardrails
|
|
89
|
+
* - `beforeTurn`: auditTrail runs first; if it blocks, hipaaGuardrails is skipped
|
|
90
|
+
* - `afterTurn`: hipaaGuardrails runs first (reverse), then auditTrail
|
|
91
|
+
*
|
|
92
|
+
* If you want the guardrail to run *before* the audit trail logs, place it
|
|
93
|
+
* first in the array: `[hipaaGuardrails, auditTrail]`.
|
|
94
|
+
*
|
|
95
|
+
* @typeParam S - The shape of per-session state. Defaults to `any` so that
|
|
96
|
+
* reusable, state-agnostic middleware (e.g. loggers, rate-limiters) can be
|
|
97
|
+
* authored without threading a state generic. Use an explicit generic
|
|
98
|
+
* (`Middleware<MyState>`) when the middleware reads or writes session state.
|
|
99
|
+
*
|
|
100
|
+
* @public
|
|
101
|
+
*/
|
|
102
|
+
export type Middleware<S = any> = {
|
|
103
|
+
/** Human-readable name for logging and debugging. */
|
|
104
|
+
name: string;
|
|
105
|
+
/**
|
|
106
|
+
* Filters user input text before it reaches the LLM. Return the
|
|
107
|
+
* (possibly modified) text. Runs on every user transcript, before
|
|
108
|
+
* `beforeTurn`.
|
|
109
|
+
*
|
|
110
|
+
* Use this to redact PII (SSNs, emails, patient IDs) from speech
|
|
111
|
+
* transcripts so the LLM never sees sensitive data.
|
|
112
|
+
*
|
|
113
|
+
* Middleware is piped in array order: the output of one filter becomes
|
|
114
|
+
* the input of the next.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* beforeInput: (text) =>
|
|
119
|
+
* text.replace(/\b\d{3}[-.]?\d{2}[-.]?\d{4}\b/g, "[SSN REDACTED]")
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
beforeInput?: (text: string, ctx: HookContext<S>) => string | Promise<string>;
|
|
123
|
+
/**
|
|
124
|
+
* Runs before each user turn. Can block the turn by returning
|
|
125
|
+
* `{ block: true, reason: "..." }`. Return `undefined` to proceed.
|
|
126
|
+
*
|
|
127
|
+
* Receives the text *after* `beforeInput` filtering has been applied.
|
|
128
|
+
*
|
|
129
|
+
* When a turn is blocked, subsequent `beforeTurn` middleware is skipped,
|
|
130
|
+
* and `afterTurn` hooks do **not** fire.
|
|
131
|
+
*/
|
|
132
|
+
beforeTurn?: (text: string, ctx: HookContext<S>) => MiddlewareBlockResult | void | undefined | Promise<MiddlewareBlockResult | void | undefined>;
|
|
133
|
+
/**
|
|
134
|
+
* Runs after each user turn completes (after all steps finish).
|
|
135
|
+
* Runs in reverse array order.
|
|
136
|
+
*/
|
|
137
|
+
afterTurn?: (text: string, ctx: HookContext<S>) => void | Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Runs before each tool call. Can approve, deny, transform args, or
|
|
140
|
+
* return a cached result.
|
|
141
|
+
*/
|
|
142
|
+
beforeToolCall?: (toolName: string, args: Readonly<Record<string, unknown>>, ctx: HookContext<S>) => ToolCallInterceptResult | undefined | Promise<ToolCallInterceptResult | undefined>;
|
|
143
|
+
/**
|
|
144
|
+
* Runs after each tool call completes. Useful for caching results,
|
|
145
|
+
* logging, or analytics. Runs in reverse array order.
|
|
146
|
+
*/
|
|
147
|
+
afterToolCall?: (toolName: string, args: Readonly<Record<string, unknown>>, result: string, ctx: HookContext<S>) => void | Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Filters agent text output before it is sent to TTS. Return the
|
|
150
|
+
* (possibly modified) text. Runs on every agent transcript chunk.
|
|
151
|
+
*/
|
|
152
|
+
beforeOutput?: (text: string, ctx: HookContext<S>) => string | Promise<string>;
|
|
153
|
+
};
|
|
14
154
|
/**
|
|
15
155
|
* Identifier for a built-in server-side tool.
|
|
16
156
|
*
|
|
@@ -18,7 +158,7 @@ export type BeforeStepResult = {
|
|
|
18
158
|
* and provide capabilities like web search, code execution, and API access.
|
|
19
159
|
*
|
|
20
160
|
* - `"web_search"` — Search the web for current information, facts, or news.
|
|
21
|
-
* - `"visit_webpage"` — Fetch a URL and return its content as
|
|
161
|
+
* - `"visit_webpage"` — Fetch a URL and return its content as clean text.
|
|
22
162
|
* - `"fetch_json"` — Call a REST API endpoint and return the JSON response.
|
|
23
163
|
* - `"run_code"` — Execute JavaScript in a sandbox for calculations and data processing.
|
|
24
164
|
* - `"vector_search"` — Search the agent's RAG knowledge base for relevant documents.
|
|
@@ -34,6 +174,8 @@ export type BuiltinTool = "web_search" | "visit_webpage" | "fetch_json" | "run_c
|
|
|
34
174
|
* - `"required"` — The model must call at least one tool.
|
|
35
175
|
* - `"none"` — Tool calling is disabled.
|
|
36
176
|
* - `{ type: "tool"; toolName: string }` — Force a specific tool.
|
|
177
|
+
*
|
|
178
|
+
* @public
|
|
37
179
|
*/
|
|
38
180
|
export type ToolChoice = "auto" | "required" | "none" | {
|
|
39
181
|
type: "tool";
|
|
@@ -90,6 +232,30 @@ export type ToolContext<S = Record<string, unknown>> = {
|
|
|
90
232
|
vector: VectorStore;
|
|
91
233
|
/** Read-only snapshot of conversation messages so far. */
|
|
92
234
|
messages: readonly Message[];
|
|
235
|
+
/**
|
|
236
|
+
* Push an intermediate update to the client UI before the tool finishes.
|
|
237
|
+
*
|
|
238
|
+
* Use this to send progressive data so the UI can render partial results
|
|
239
|
+
* immediately (e.g. a loading card, preview, or streaming data) instead
|
|
240
|
+
* of waiting for the full tool result.
|
|
241
|
+
*
|
|
242
|
+
* The data is serialized to JSON and delivered as a `tool_call_update`
|
|
243
|
+
* event on the client. Use `useToolCallUpdate` in the UI to consume it.
|
|
244
|
+
*
|
|
245
|
+
* No-op in sandbox (platform) mode.
|
|
246
|
+
*/
|
|
247
|
+
sendUpdate(data: unknown): void;
|
|
248
|
+
/**
|
|
249
|
+
* SSRF-safe fetch function.
|
|
250
|
+
*
|
|
251
|
+
* In self-hosted mode this calls the network directly (with SSRF protection).
|
|
252
|
+
* In platform mode this is proxied through the sidecar so it works inside
|
|
253
|
+
* the sandbox. Always use `ctx.fetch` instead of the global `fetch` in tool
|
|
254
|
+
* code to ensure portability across both deployment modes.
|
|
255
|
+
*/
|
|
256
|
+
fetch: typeof globalThis.fetch;
|
|
257
|
+
/** Unique identifier for the current session. Useful for correlating logs across concurrent sessions. */
|
|
258
|
+
sessionId: string;
|
|
93
259
|
};
|
|
94
260
|
/**
|
|
95
261
|
* Context passed to lifecycle hooks (`onConnect`, `onTurn`, etc.).
|
|
@@ -102,7 +268,7 @@ export type ToolContext<S = Record<string, unknown>> = {
|
|
|
102
268
|
*
|
|
103
269
|
* @public
|
|
104
270
|
*/
|
|
105
|
-
export type HookContext<S = Record<string, unknown>> = Omit<ToolContext<S>, "messages">;
|
|
271
|
+
export type HookContext<S = Record<string, unknown>> = Omit<ToolContext<S>, "messages" | "sendUpdate">;
|
|
106
272
|
/**
|
|
107
273
|
* Definition of a custom tool that the agent can invoke.
|
|
108
274
|
*
|
|
@@ -139,7 +305,7 @@ export type ToolDef<P extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawS
|
|
|
139
305
|
/** Human-readable description shown to the LLM. */
|
|
140
306
|
description: string;
|
|
141
307
|
/** Zod schema for the tool's parameters. */
|
|
142
|
-
parameters?: P
|
|
308
|
+
parameters?: P;
|
|
143
309
|
/** Function that executes the tool and returns a result. */
|
|
144
310
|
execute(args: z.infer<P>, ctx: ToolContext<S>): Promise<unknown> | unknown;
|
|
145
311
|
};
|
|
@@ -148,18 +314,19 @@ export type ToolDef<P extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawS
|
|
|
148
314
|
*
|
|
149
315
|
* When tools are defined inline in `defineAgent({ tools: { ... } })`, the
|
|
150
316
|
* generic `P` gets widened to the base `ZodObject` type, so `args` in
|
|
151
|
-
* `execute` loses its specific shape. Wrapping a tool definition in
|
|
152
|
-
* lets TypeScript infer `P` from `parameters` and type
|
|
317
|
+
* `execute` loses its specific shape. Wrapping a tool definition in
|
|
318
|
+
* `defineTool()` lets TypeScript infer `P` from `parameters` and type
|
|
319
|
+
* `args` correctly.
|
|
153
320
|
*
|
|
154
321
|
* @example
|
|
155
322
|
* ```ts
|
|
156
|
-
* import { defineAgent,
|
|
323
|
+
* import { defineAgent, defineTool } from "aai";
|
|
157
324
|
* import { z } from "zod";
|
|
158
325
|
*
|
|
159
326
|
* export default defineAgent({
|
|
160
327
|
* name: "my-agent",
|
|
161
328
|
* tools: {
|
|
162
|
-
* greet:
|
|
329
|
+
* greet: defineTool({
|
|
163
330
|
* description: "Greet the user",
|
|
164
331
|
* parameters: z.object({ name: z.string() }),
|
|
165
332
|
* execute: ({ name }) => `Hello, ${name}!`, // name is string
|
|
@@ -170,7 +337,82 @@ export type ToolDef<P extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawS
|
|
|
170
337
|
*
|
|
171
338
|
* @public
|
|
172
339
|
*/
|
|
173
|
-
export declare function
|
|
340
|
+
export declare function defineTool<P extends z.ZodObject<z.ZodRawShape>, S = Record<string, unknown>>(def: ToolDef<P, S>): ToolDef<P, S>;
|
|
341
|
+
/** Alias for {@link defineTool}. Prefer `defineTool` for clarity. */
|
|
342
|
+
export { defineTool as tool };
|
|
343
|
+
/**
|
|
344
|
+
* Create a typed `defineTool` helper with the session state type baked in.
|
|
345
|
+
*
|
|
346
|
+
* When tools need access to typed session state, you'd normally have to write
|
|
347
|
+
* verbose generics on every `defineTool` call. `createToolFactory` eliminates
|
|
348
|
+
* that boilerplate by returning a `defineTool` variant that already knows `S`.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* import { createToolFactory, defineAgent } from "aai";
|
|
353
|
+
* import { z } from "zod";
|
|
354
|
+
*
|
|
355
|
+
* interface PortfolioState { holdings: Map<string, number> }
|
|
356
|
+
*
|
|
357
|
+
* const tool = createToolFactory<PortfolioState>();
|
|
358
|
+
*
|
|
359
|
+
* export default defineAgent<PortfolioState>({
|
|
360
|
+
* name: "portfolio",
|
|
361
|
+
* state: () => ({ holdings: new Map() }),
|
|
362
|
+
* tools: {
|
|
363
|
+
* buy: tool({
|
|
364
|
+
* description: "Buy shares",
|
|
365
|
+
* parameters: z.object({ symbol: z.string(), qty: z.number() }),
|
|
366
|
+
* execute: (args, ctx) => {
|
|
367
|
+
* // args.symbol is string, ctx.state is PortfolioState
|
|
368
|
+
* ctx.state.holdings.set(args.symbol, args.qty);
|
|
369
|
+
* },
|
|
370
|
+
* }),
|
|
371
|
+
* },
|
|
372
|
+
* });
|
|
373
|
+
* ```
|
|
374
|
+
*
|
|
375
|
+
* @public
|
|
376
|
+
*/
|
|
377
|
+
export declare function createToolFactory<S = Record<string, unknown>>(): <P extends z.ZodObject<z.ZodRawShape>>(def: ToolDef<P, S>) => ToolDef<P, S>;
|
|
378
|
+
/**
|
|
379
|
+
* A mapping of tool names to their result types.
|
|
380
|
+
*
|
|
381
|
+
* Define this in a shared file (e.g. `shared.ts`) that both `agent.ts` and
|
|
382
|
+
* `client.tsx` can import, so tool result types stay in sync without
|
|
383
|
+
* duplication.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```ts
|
|
387
|
+
* // shared.ts
|
|
388
|
+
* import type { ToolResultMap } from "@alexkroman1/aai";
|
|
389
|
+
*
|
|
390
|
+
* export interface Pizza {
|
|
391
|
+
* id: number;
|
|
392
|
+
* size: "small" | "medium" | "large";
|
|
393
|
+
* toppings: string[];
|
|
394
|
+
* }
|
|
395
|
+
*
|
|
396
|
+
* export type MyToolResults = ToolResultMap<{
|
|
397
|
+
* add_pizza: { added: Pizza; orderTotal: string };
|
|
398
|
+
* place_order: { orderNumber: number; total: string };
|
|
399
|
+
* }>;
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* Then use with {@link @alexkroman1/aai-ui#useToolResult | useToolResult}:
|
|
403
|
+
*
|
|
404
|
+
* ```tsx
|
|
405
|
+
* // client.tsx
|
|
406
|
+
* import type { MyToolResults } from "./shared.ts";
|
|
407
|
+
*
|
|
408
|
+
* useToolResult<MyToolResults["add_pizza"]>("add_pizza", (result) => {
|
|
409
|
+
* console.log(result.added); // fully typed
|
|
410
|
+
* });
|
|
411
|
+
* ```
|
|
412
|
+
*
|
|
413
|
+
* @public
|
|
414
|
+
*/
|
|
415
|
+
export type ToolResultMap<T extends Record<string, unknown> = Record<string, unknown>> = T;
|
|
174
416
|
/**
|
|
175
417
|
* Information about a completed agentic step, passed to the `onStep` hook.
|
|
176
418
|
*
|
|
@@ -206,7 +448,6 @@ export type StepInfo = {
|
|
|
206
448
|
* export default defineAgent({
|
|
207
449
|
* name: "research-bot",
|
|
208
450
|
* instructions: "You help users research topics.",
|
|
209
|
-
* voice: "orion",
|
|
210
451
|
* builtinTools: ["web_search"],
|
|
211
452
|
* tools: {
|
|
212
453
|
* summarize: {
|
|
@@ -240,17 +481,25 @@ export type AgentOptions<S = Record<string, unknown>> = {
|
|
|
240
481
|
toolChoice?: ToolChoice;
|
|
241
482
|
/** Built-in tools to enable (e.g. `"web_search"`, `"run_code"`). */
|
|
242
483
|
builtinTools?: readonly BuiltinTool[];
|
|
243
|
-
/**
|
|
244
|
-
* Default set of active tools per turn.
|
|
245
|
-
*
|
|
246
|
-
* When set, only these tools are available to the LLM each turn.
|
|
247
|
-
* Can be overridden dynamically per-turn via `onBeforeStep`.
|
|
248
|
-
*/
|
|
249
|
-
activeTools?: readonly string[];
|
|
250
484
|
/** Custom tools the agent can invoke. */
|
|
251
485
|
tools?: Readonly<Record<string, ToolDef<z.ZodObject<z.ZodRawShape>, NoInfer<S>>>>;
|
|
252
486
|
/** Factory that creates fresh per-session state. Called once per connection. */
|
|
253
487
|
state?: () => S;
|
|
488
|
+
/**
|
|
489
|
+
* Enable automatic session state persistence across reconnects.
|
|
490
|
+
*
|
|
491
|
+
* When enabled, session state, conversation history, and the S2S session ID
|
|
492
|
+
* are saved to KV on disconnect and restored when the client reconnects with
|
|
493
|
+
* `?sessionId=<old-session-id>` in the WebSocket URL.
|
|
494
|
+
*
|
|
495
|
+
* - `true` — enable with default TTL (1 hour)
|
|
496
|
+
* - `{ ttl: number }` — enable with custom TTL in milliseconds
|
|
497
|
+
*
|
|
498
|
+
* Requires the agent's `state` return value to be JSON-serializable.
|
|
499
|
+
*/
|
|
500
|
+
persistence?: boolean | {
|
|
501
|
+
ttl?: number;
|
|
502
|
+
};
|
|
254
503
|
/** Called when a new session connects. */
|
|
255
504
|
onConnect?: (ctx: HookContext<S>) => void | Promise<void>;
|
|
256
505
|
/** Called when a session disconnects. */
|
|
@@ -262,12 +511,23 @@ export type AgentOptions<S = Record<string, unknown>> = {
|
|
|
262
511
|
/** Called after each agentic step completes. */
|
|
263
512
|
onStep?: (step: StepInfo, ctx: HookContext<S>) => void | Promise<void>;
|
|
264
513
|
/**
|
|
265
|
-
*
|
|
514
|
+
* Composable middleware that intercepts turns, tool calls, and output.
|
|
266
515
|
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
516
|
+
* Middleware runs in array order for "before" hooks (first to last)
|
|
517
|
+
* and reverse order for "after" hooks (last to first).
|
|
269
518
|
*/
|
|
270
|
-
|
|
519
|
+
middleware?: readonly Middleware<S>[];
|
|
520
|
+
/**
|
|
521
|
+
* Close the S2S connection after this many milliseconds of inactivity.
|
|
522
|
+
* Inactivity means no audio, transcripts, or tool calls in either direction.
|
|
523
|
+
* When the timeout fires the session is stopped and the client receives an
|
|
524
|
+
* `idle_timeout` event.
|
|
525
|
+
*
|
|
526
|
+
* Set to `0` or `Infinity` to disable.
|
|
527
|
+
*
|
|
528
|
+
* @defaultValue 300_000 (5 minutes)
|
|
529
|
+
*/
|
|
530
|
+
idleTimeoutMs?: number;
|
|
271
531
|
};
|
|
272
532
|
/**
|
|
273
533
|
* Default system prompt used when `instructions` is not provided.
|
|
@@ -279,30 +539,55 @@ export declare const DEFAULT_INSTRUCTIONS: string;
|
|
|
279
539
|
/** Default greeting spoken when a session starts. */
|
|
280
540
|
export declare const DEFAULT_GREETING: string;
|
|
281
541
|
/**
|
|
282
|
-
* Agent definition
|
|
283
|
-
*
|
|
542
|
+
* Agent definition returned by {@link defineAgent}.
|
|
543
|
+
*
|
|
544
|
+
* Core fields (`name`, `instructions`, `greeting`, `maxSteps`, `tools`)
|
|
545
|
+
* are resolved to their final values with defaults applied. Optional
|
|
546
|
+
* behavioral fields (hooks, middleware, `sttPrompt`, etc.) remain
|
|
547
|
+
* optional — `undefined` means "not configured."
|
|
284
548
|
*
|
|
285
|
-
*
|
|
286
|
-
* final value — no optional fields with implicit defaults remain.
|
|
549
|
+
* @public
|
|
287
550
|
*/
|
|
288
|
-
export type AgentDef = {
|
|
551
|
+
export type AgentDef<S = Record<string, unknown>> = {
|
|
289
552
|
name: string;
|
|
290
553
|
instructions: string;
|
|
291
554
|
greeting: string;
|
|
292
555
|
sttPrompt?: string;
|
|
293
|
-
maxSteps: number | ((ctx: HookContext) => number);
|
|
556
|
+
maxSteps: number | ((ctx: HookContext<S>) => number);
|
|
294
557
|
toolChoice?: ToolChoice;
|
|
295
558
|
builtinTools?: readonly BuiltinTool[];
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
559
|
+
tools: Readonly<Record<string, ToolDef<z.ZodObject<z.ZodRawShape>, S>>>;
|
|
560
|
+
state?: () => S;
|
|
561
|
+
/** Resolved persistence config, or `undefined` if disabled. */
|
|
562
|
+
persistence?: {
|
|
563
|
+
ttl: number;
|
|
564
|
+
};
|
|
565
|
+
onConnect?: (ctx: HookContext<S>) => void | Promise<void>;
|
|
566
|
+
onDisconnect?: (ctx: HookContext<S>) => void | Promise<void>;
|
|
567
|
+
onError?: (error: Error, ctx?: HookContext<S>) => void;
|
|
568
|
+
onTurn?: (text: string, ctx: HookContext<S>) => void | Promise<void>;
|
|
569
|
+
onStep?: (step: StepInfo, ctx: HookContext<S>) => void | Promise<void>;
|
|
570
|
+
middleware?: readonly Middleware<S>[];
|
|
571
|
+
idleTimeoutMs?: number;
|
|
305
572
|
};
|
|
573
|
+
/** @internal Zod schema for {@link BuiltinTool}. Exported for reuse in internal schemas. */
|
|
574
|
+
export declare const BuiltinToolSchema: z.ZodEnum<{
|
|
575
|
+
web_search: "web_search";
|
|
576
|
+
visit_webpage: "visit_webpage";
|
|
577
|
+
fetch_json: "fetch_json";
|
|
578
|
+
run_code: "run_code";
|
|
579
|
+
vector_search: "vector_search";
|
|
580
|
+
memory: "memory";
|
|
581
|
+
}>;
|
|
582
|
+
/** @internal Zod schema for {@link ToolChoice}. Exported for reuse in internal schemas. */
|
|
583
|
+
export declare const ToolChoiceSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
584
|
+
auto: "auto";
|
|
585
|
+
required: "required";
|
|
586
|
+
none: "none";
|
|
587
|
+
}>, z.ZodObject<{
|
|
588
|
+
type: z.ZodLiteral<"tool">;
|
|
589
|
+
toolName: z.ZodString;
|
|
590
|
+
}, z.core.$strip>]>;
|
|
306
591
|
/**
|
|
307
592
|
* Create an agent definition from the given options, applying sensible defaults.
|
|
308
593
|
*
|
|
@@ -333,4 +618,4 @@ export type AgentDef = {
|
|
|
333
618
|
* });
|
|
334
619
|
* ```
|
|
335
620
|
*/
|
|
336
|
-
export declare function defineAgent<S
|
|
621
|
+
export declare function defineAgent<S = Record<string, unknown>>(options: AgentOptions<S>): AgentDef<S>;
|
package/dist/types.js
CHANGED
|
@@ -8,18 +8,19 @@ import { z } from "zod";
|
|
|
8
8
|
*
|
|
9
9
|
* When tools are defined inline in `defineAgent({ tools: { ... } })`, the
|
|
10
10
|
* generic `P` gets widened to the base `ZodObject` type, so `args` in
|
|
11
|
-
* `execute` loses its specific shape. Wrapping a tool definition in
|
|
12
|
-
* lets TypeScript infer `P` from `parameters` and type
|
|
11
|
+
* `execute` loses its specific shape. Wrapping a tool definition in
|
|
12
|
+
* `defineTool()` lets TypeScript infer `P` from `parameters` and type
|
|
13
|
+
* `args` correctly.
|
|
13
14
|
*
|
|
14
15
|
* @example
|
|
15
16
|
* ```ts
|
|
16
|
-
* import { defineAgent,
|
|
17
|
+
* import { defineAgent, defineTool } from "aai";
|
|
17
18
|
* import { z } from "zod";
|
|
18
19
|
*
|
|
19
20
|
* export default defineAgent({
|
|
20
21
|
* name: "my-agent",
|
|
21
22
|
* tools: {
|
|
22
|
-
* greet:
|
|
23
|
+
* greet: defineTool({
|
|
23
24
|
* description: "Greet the user",
|
|
24
25
|
* parameters: z.object({ name: z.string() }),
|
|
25
26
|
* execute: ({ name }) => `Hello, ${name}!`, // name is string
|
|
@@ -30,10 +31,47 @@ import { z } from "zod";
|
|
|
30
31
|
*
|
|
31
32
|
* @public
|
|
32
33
|
*/
|
|
33
|
-
function
|
|
34
|
+
function defineTool(def) {
|
|
34
35
|
return def;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
38
|
+
* Create a typed `defineTool` helper with the session state type baked in.
|
|
39
|
+
*
|
|
40
|
+
* When tools need access to typed session state, you'd normally have to write
|
|
41
|
+
* verbose generics on every `defineTool` call. `createToolFactory` eliminates
|
|
42
|
+
* that boilerplate by returning a `defineTool` variant that already knows `S`.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { createToolFactory, defineAgent } from "aai";
|
|
47
|
+
* import { z } from "zod";
|
|
48
|
+
*
|
|
49
|
+
* interface PortfolioState { holdings: Map<string, number> }
|
|
50
|
+
*
|
|
51
|
+
* const tool = createToolFactory<PortfolioState>();
|
|
52
|
+
*
|
|
53
|
+
* export default defineAgent<PortfolioState>({
|
|
54
|
+
* name: "portfolio",
|
|
55
|
+
* state: () => ({ holdings: new Map() }),
|
|
56
|
+
* tools: {
|
|
57
|
+
* buy: tool({
|
|
58
|
+
* description: "Buy shares",
|
|
59
|
+
* parameters: z.object({ symbol: z.string(), qty: z.number() }),
|
|
60
|
+
* execute: (args, ctx) => {
|
|
61
|
+
* // args.symbol is string, ctx.state is PortfolioState
|
|
62
|
+
* ctx.state.holdings.set(args.symbol, args.qty);
|
|
63
|
+
* },
|
|
64
|
+
* }),
|
|
65
|
+
* },
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @public
|
|
70
|
+
*/
|
|
71
|
+
function createToolFactory() {
|
|
72
|
+
return (def) => def;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
37
75
|
* Default system prompt used when `instructions` is not provided.
|
|
38
76
|
*
|
|
39
77
|
* Optimized for voice-first interactions: short sentences, no visual
|
|
@@ -56,6 +94,7 @@ If you need to list items, say "First," "Next," and "Finally."
|
|
|
56
94
|
- Never use exclamation points. Keep your tone calm and conversational.`;
|
|
57
95
|
/** Default greeting spoken when a session starts. */
|
|
58
96
|
const DEFAULT_GREETING = "Hey there. I'm a voice assistant. What can I help you with?";
|
|
97
|
+
/** @internal Zod schema for {@link BuiltinTool}. Exported for reuse in internal schemas. */
|
|
59
98
|
const BuiltinToolSchema = z.enum([
|
|
60
99
|
"web_search",
|
|
61
100
|
"visit_webpage",
|
|
@@ -64,6 +103,7 @@ const BuiltinToolSchema = z.enum([
|
|
|
64
103
|
"vector_search",
|
|
65
104
|
"memory"
|
|
66
105
|
]);
|
|
106
|
+
/** @internal Zod schema for {@link ToolChoice}. Exported for reuse in internal schemas. */
|
|
67
107
|
const ToolChoiceSchema = z.union([z.enum([
|
|
68
108
|
"auto",
|
|
69
109
|
"required",
|
|
@@ -77,6 +117,8 @@ const ToolDefSchema = z.object({
|
|
|
77
117
|
parameters: z.custom((val) => val === void 0 || val instanceof z.ZodType, "Expected a Zod schema").optional(),
|
|
78
118
|
execute: z.function()
|
|
79
119
|
});
|
|
120
|
+
/** Default TTL for persisted session data: 1 hour. */
|
|
121
|
+
const DEFAULT_PERSIST_TTL = 36e5;
|
|
80
122
|
const AgentOptionsSchema = z.object({
|
|
81
123
|
name: z.string().min(1, "Agent name must be non-empty"),
|
|
82
124
|
instructions: z.string().optional(),
|
|
@@ -85,15 +127,24 @@ const AgentOptionsSchema = z.object({
|
|
|
85
127
|
maxSteps: z.union([z.number().int().positive(), z.function()]).optional(),
|
|
86
128
|
toolChoice: ToolChoiceSchema.optional(),
|
|
87
129
|
builtinTools: z.array(BuiltinToolSchema).optional(),
|
|
88
|
-
activeTools: z.array(z.string().min(1)).optional(),
|
|
89
130
|
tools: z.record(z.string(), ToolDefSchema).optional(),
|
|
90
131
|
state: z.function().optional(),
|
|
132
|
+
persistence: z.union([z.literal(true), z.object({ ttl: z.number().int().positive().optional() })]).optional(),
|
|
91
133
|
onConnect: z.function().optional(),
|
|
92
134
|
onDisconnect: z.function().optional(),
|
|
93
135
|
onError: z.function().optional(),
|
|
94
136
|
onTurn: z.function().optional(),
|
|
95
137
|
onStep: z.function().optional(),
|
|
96
|
-
|
|
138
|
+
middleware: z.array(z.object({
|
|
139
|
+
name: z.string().min(1, "Middleware name must be non-empty"),
|
|
140
|
+
beforeInput: z.function().optional(),
|
|
141
|
+
beforeTurn: z.function().optional(),
|
|
142
|
+
afterTurn: z.function().optional(),
|
|
143
|
+
beforeToolCall: z.function().optional(),
|
|
144
|
+
afterToolCall: z.function().optional(),
|
|
145
|
+
beforeOutput: z.function().optional()
|
|
146
|
+
})).optional(),
|
|
147
|
+
idleTimeoutMs: z.number().nonnegative().optional()
|
|
97
148
|
});
|
|
98
149
|
/**
|
|
99
150
|
* Create an agent definition from the given options, applying sensible defaults.
|
|
@@ -127,13 +178,15 @@ const AgentOptionsSchema = z.object({
|
|
|
127
178
|
*/
|
|
128
179
|
function defineAgent(options) {
|
|
129
180
|
AgentOptionsSchema.parse(options);
|
|
181
|
+
const persistence = options.persistence ? { ttl: typeof options.persistence === "object" ? options.persistence.ttl ?? DEFAULT_PERSIST_TTL : DEFAULT_PERSIST_TTL } : void 0;
|
|
130
182
|
return {
|
|
131
183
|
...options,
|
|
132
184
|
instructions: options.instructions ?? DEFAULT_INSTRUCTIONS,
|
|
133
185
|
greeting: options.greeting ?? "Hey there. I'm a voice assistant. What can I help you with?",
|
|
134
186
|
maxSteps: options.maxSteps ?? 5,
|
|
135
|
-
tools: options.tools ?? {}
|
|
187
|
+
tools: options.tools ?? {},
|
|
188
|
+
persistence
|
|
136
189
|
};
|
|
137
190
|
}
|
|
138
191
|
//#endregion
|
|
139
|
-
export { DEFAULT_GREETING, DEFAULT_INSTRUCTIONS, defineAgent, tool };
|
|
192
|
+
export { BuiltinToolSchema, DEFAULT_GREETING, DEFAULT_INSTRUCTIONS, ToolChoiceSchema, createToolFactory, defineAgent, defineTool, defineTool as tool };
|
package/dist/vector.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vector store interface
|
|
2
|
+
* Vector store interface.
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validate a vector filter expression to prevent injection attacks.
|
|
6
|
+
*
|
|
7
|
+
* Rejects filters containing SQL keywords (SELECT, DROP, etc.),
|
|
8
|
+
* statement terminators, comments, and null bytes. Enforces a
|
|
9
|
+
* maximum length of 1000 characters.
|
|
10
|
+
*
|
|
11
|
+
* @param filter - The raw filter string from user input.
|
|
12
|
+
* @returns The validated filter string (trimmed).
|
|
13
|
+
* @throws Error if the filter contains dangerous patterns.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateVectorFilter(filter: string): string;
|
|
4
18
|
/**
|
|
5
19
|
* A single vector search result entry.
|
|
6
20
|
*
|
|
@@ -63,27 +77,9 @@ export type VectorStore = {
|
|
|
63
77
|
filter?: string;
|
|
64
78
|
}): Promise<VectorEntry[]>;
|
|
65
79
|
/**
|
|
66
|
-
*
|
|
80
|
+
* Delete entries by ID.
|
|
67
81
|
*
|
|
68
|
-
* @param ids - A single ID or array of IDs to
|
|
82
|
+
* @param ids - A single ID or array of IDs to delete.
|
|
69
83
|
*/
|
|
70
|
-
|
|
84
|
+
delete(ids: string | string[]): Promise<void>;
|
|
71
85
|
};
|
|
72
|
-
/**
|
|
73
|
-
* Create an in-memory vector store for testing and local development.
|
|
74
|
-
*
|
|
75
|
-
* Uses brute-force substring matching instead of real vector similarity.
|
|
76
|
-
* Good enough for testing the plumbing but not for production use.
|
|
77
|
-
*
|
|
78
|
-
* @returns A {@link VectorStore} instance backed by in-memory storage.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* import { createMemoryVectorStore } from "aai";
|
|
83
|
-
*
|
|
84
|
-
* const vector = createMemoryVectorStore();
|
|
85
|
-
* await vector.upsert("doc-1", "The capital of France is Paris.");
|
|
86
|
-
* const results = await vector.query("France capital");
|
|
87
|
-
* ```
|
|
88
|
-
*/
|
|
89
|
-
export declare function createMemoryVectorStore(): VectorStore;
|