@alexkroman1/aai 0.9.2 → 0.10.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.
Files changed (57) hide show
  1. package/dist/_internal-types.d.ts +49 -22
  2. package/dist/_internal-types.js +43 -1
  3. package/dist/_mock-ws.d.ts +1 -2
  4. package/dist/_run-code.d.ts +31 -0
  5. package/dist/_session-ctx.d.ts +73 -0
  6. package/dist/_session-otel.d.ts +43 -0
  7. package/dist/_session-persist.d.ts +30 -0
  8. package/dist/_ssrf.d.ts +30 -0
  9. package/dist/_ssrf.js +123 -0
  10. package/dist/_utils.d.ts +25 -0
  11. package/dist/_utils.js +54 -1
  12. package/dist/builtin-tools.d.ts +5 -34
  13. package/dist/direct-executor-Ca0wt5H0.js +572 -0
  14. package/dist/direct-executor.d.ts +34 -5
  15. package/dist/index.d.ts +2 -1
  16. package/dist/index.js +2 -2
  17. package/dist/kv.d.ts +30 -38
  18. package/dist/kv.js +19 -86
  19. package/dist/matchers.d.ts +20 -0
  20. package/dist/matchers.js +41 -0
  21. package/dist/memory-tools.d.ts +39 -0
  22. package/dist/middleware-core.d.ts +47 -0
  23. package/dist/middleware-core.js +107 -0
  24. package/dist/middleware.d.ts +37 -0
  25. package/dist/protocol.d.ts +44 -24
  26. package/dist/protocol.js +34 -14
  27. package/dist/runtime.d.ts +26 -2
  28. package/dist/runtime.js +44 -7
  29. package/dist/s2s.d.ts +19 -29
  30. package/dist/s2s.js +117 -87
  31. package/dist/server.d.ts +31 -3
  32. package/dist/server.js +102 -28
  33. package/dist/session-BkN9u0ni.js +683 -0
  34. package/dist/session.d.ts +55 -28
  35. package/dist/session.js +2 -312
  36. package/dist/sqlite-kv.d.ts +34 -0
  37. package/dist/sqlite-kv.js +133 -0
  38. package/dist/sqlite-vector.d.ts +58 -0
  39. package/dist/sqlite-vector.js +149 -0
  40. package/dist/system-prompt.d.ts +21 -0
  41. package/dist/telemetry.d.ts +49 -0
  42. package/dist/telemetry.js +95 -0
  43. package/dist/testing-MRl3SXsI.js +519 -0
  44. package/dist/testing.d.ts +299 -0
  45. package/dist/testing.js +2 -0
  46. package/dist/types.d.ts +324 -39
  47. package/dist/types.js +62 -9
  48. package/dist/vector.d.ts +18 -22
  49. package/dist/vector.js +41 -48
  50. package/dist/worker-entry.d.ts +11 -3
  51. package/dist/worker-entry.js +19 -8
  52. package/dist/ws-handler.d.ts +7 -3
  53. package/dist/ws-handler.js +64 -12
  54. package/package.json +55 -8
  55. package/dist/_mock-ws.js +0 -158
  56. package/dist/builtin-tools.js +0 -270
  57. package/dist/direct-executor.js +0 -125
package/dist/kv.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
- * Key-value storage interface and in-memory implementation.
2
+ * Key-value storage interface and shared utilities.
3
3
  */
4
4
  /**
5
5
  * A single key-value entry returned by {@link Kv.list}.
6
6
  *
7
7
  * @typeParam T - The type of the stored value. Defaults to `unknown`.
8
+ *
9
+ * @public
8
10
  */
9
11
  export type KvEntry<T = unknown> = {
10
12
  /** The key under which the value is stored. */
@@ -15,7 +17,10 @@ export type KvEntry<T = unknown> = {
15
17
  /**
16
18
  * Options for listing keys from the KV store.
17
19
  *
18
- * Used with {@link Kv.list} to control result ordering and pagination.
20
+ * Used with {@link Kv.list} and {@link Kv.keys} to control filtering,
21
+ * ordering, and pagination.
22
+ *
23
+ * @public
19
24
  */
20
25
  export type KvListOptions = {
21
26
  /** Maximum number of entries to return. */
@@ -26,8 +31,8 @@ export type KvListOptions = {
26
31
  /**
27
32
  * Async key-value store interface used by agents.
28
33
  *
29
- * Agents access the KV store via {@link ToolContext.kv} or
30
- * {@link HookContext.kv}. Values are JSON-serialized and stored as
34
+ * Agents access the KV store via `ToolContext.kv` or
35
+ * `HookContext.kv`. Values are JSON-serialized and stored as
31
36
  * strings with an optional TTL.
32
37
  *
33
38
  * @example
@@ -42,6 +47,8 @@ export type KvListOptions = {
42
47
  * },
43
48
  * };
44
49
  * ```
50
+ *
51
+ * @public
45
52
  */
46
53
  export type Kv = {
47
54
  /**
@@ -58,19 +65,19 @@ export type Kv = {
58
65
  *
59
66
  * @param key - The key to store the value under.
60
67
  * @param value - The value to store. Must be JSON-serializable.
61
- * @param options - Optional settings. `expireIn` sets the time-to-live in milliseconds. The entry is
62
- * automatically removed after this duration.
63
- * @throws {Error} If the serialized value exceeds 65,536 bytes.
68
+ * @param options - Optional settings. `expireIn` sets the time-to-live in **milliseconds**
69
+ * (e.g. `60_000` for 1 minute). The entry is automatically removed after this duration.
70
+ * @throws Throws an Error if the serialized value exceeds 65,536 bytes.
64
71
  */
65
72
  set(key: string, value: unknown, options?: {
66
73
  expireIn?: number;
67
74
  }): Promise<void>;
68
75
  /**
69
- * Delete a key.
76
+ * Delete one or more keys.
70
77
  *
71
- * @param key - The key to remove. No-op if the key does not exist.
78
+ * @param keys - A single key or array of keys to delete. No-op for keys that do not exist.
72
79
  */
73
- delete(key: string): Promise<void>;
80
+ delete(keys: string | string[]): Promise<void>;
74
81
  /**
75
82
  * List entries whose keys start with the given prefix.
76
83
  *
@@ -83,12 +90,21 @@ export type Kv = {
83
90
  */
84
91
  list<T = unknown>(prefix: string, options?: KvListOptions): Promise<KvEntry<T>[]>;
85
92
  /**
86
- * List all keys, optionally filtered by a glob-style pattern.
93
+ * List all keys, optionally filtered by a prefix or glob-style pattern.
87
94
  *
88
- * @param pattern - Optional glob pattern (e.g. `"user:*"`). If omitted, all keys are returned.
95
+ * @param pattern - Optional prefix string or glob pattern (e.g. `"user:*"`).
96
+ * A pattern without wildcards (`*`) is treated as a prefix match.
97
+ * If omitted, all keys are returned.
89
98
  * @returns An array of matching key strings.
90
99
  */
91
100
  keys(pattern?: string): Promise<string[]>;
101
+ /**
102
+ * Close the KV store, releasing any resources (intervals, database handles).
103
+ *
104
+ * After calling `close()`, the store must not be used. This is a no-op
105
+ * for implementations that hold no resources (e.g. in-memory stores).
106
+ */
107
+ close?(): void;
92
108
  };
93
109
  export declare const MAX_VALUE_SIZE = 65536;
94
110
  /** Sort entries by key and apply reverse/limit options. Mutates the array. */
@@ -98,29 +114,5 @@ export declare function sortAndPaginate<T extends {
98
114
  limit?: number;
99
115
  reverse?: boolean;
100
116
  }): T[];
101
- /**
102
- * Create an in-memory KV store (useful for testing and local development).
103
- *
104
- * Data is stored in a plain `Map` and does not persist across restarts.
105
- * TTL expiration is checked lazily on reads and list operations.
106
- *
107
- * @returns A {@link Kv} instance backed by in-memory storage.
108
- *
109
- * @example
110
- * ```ts
111
- * import { createMemoryKv } from "./kv.ts";
112
- *
113
- * const kv = createMemoryKv();
114
- * await kv.set("greeting", "hello");
115
- * const value = await kv.get<string>("greeting"); // "hello"
116
- * ```
117
- *
118
- * @example With TTL
119
- * ```ts
120
- * import { createMemoryKv } from "./kv.ts";
121
- *
122
- * const kv = createMemoryKv();
123
- * await kv.set("temp", "expires soon", { expireIn: 5000 });
124
- * ```
125
- */
126
- export declare function createMemoryKv(): Kv;
117
+ /** Simple glob matcher — supports `*` as a wildcard for any characters. */
118
+ export declare function matchGlob(key: string, pattern: string): boolean;
package/dist/kv.js CHANGED
@@ -2,98 +2,31 @@
2
2
  const MAX_VALUE_SIZE = 65536;
3
3
  /** Sort entries by key and apply reverse/limit options. Mutates the array. */
4
4
  function sortAndPaginate(entries, options) {
5
- entries.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
5
+ entries.sort((a, b) => a.key.localeCompare(b.key));
6
6
  if (options?.reverse) entries.reverse();
7
7
  if (options?.limit && options.limit > 0) entries.length = Math.min(entries.length, options.limit);
8
8
  return entries;
9
9
  }
10
+ /** Maximum allowed glob pattern length to prevent ReDoS. */
11
+ const MAX_GLOB_PATTERN_LENGTH = 1024;
10
12
  /** Simple glob matcher — supports `*` as a wildcard for any characters. */
11
13
  function matchGlob(key, pattern) {
12
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
13
- return new RegExp(`^${escaped}$`).test(key);
14
- }
15
- /**
16
- * Create an in-memory KV store (useful for testing and local development).
17
- *
18
- * Data is stored in a plain `Map` and does not persist across restarts.
19
- * TTL expiration is checked lazily on reads and list operations.
20
- *
21
- * @returns A {@link Kv} instance backed by in-memory storage.
22
- *
23
- * @example
24
- * ```ts
25
- * import { createMemoryKv } from "./kv.ts";
26
- *
27
- * const kv = createMemoryKv();
28
- * await kv.set("greeting", "hello");
29
- * const value = await kv.get<string>("greeting"); // "hello"
30
- * ```
31
- *
32
- * @example With TTL
33
- * ```ts
34
- * import { createMemoryKv } from "./kv.ts";
35
- *
36
- * const kv = createMemoryKv();
37
- * await kv.set("temp", "expires soon", { expireIn: 5000 });
38
- * ```
39
- */
40
- function createMemoryKv() {
41
- const store = /* @__PURE__ */ new Map();
42
- function isExpired(entry) {
43
- return entry.expiresAt !== void 0 && entry.expiresAt <= Date.now();
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;
44
28
  }
45
- return {
46
- get(key) {
47
- const entry = store.get(key);
48
- if (!entry || isExpired(entry)) {
49
- if (entry) store.delete(key);
50
- return Promise.resolve(null);
51
- }
52
- return Promise.resolve(JSON.parse(entry.raw));
53
- },
54
- set(key, value, options) {
55
- const raw = JSON.stringify(value);
56
- if (raw.length > 65536) throw new Error(`Value exceeds max size of ${MAX_VALUE_SIZE} bytes`);
57
- const expireIn = options?.expireIn;
58
- const entry = { raw };
59
- if (expireIn && expireIn > 0) entry.expiresAt = Date.now() + expireIn;
60
- store.set(key, entry);
61
- return Promise.resolve();
62
- },
63
- delete(key) {
64
- store.delete(key);
65
- return Promise.resolve();
66
- },
67
- async list(prefix, options) {
68
- const now = Date.now();
69
- const entries = [];
70
- let i = 0;
71
- for (const [key, entry] of store) {
72
- if (++i % 500 === 0) await new Promise((r) => setTimeout(r, 0));
73
- if (entry.expiresAt && entry.expiresAt <= now) {
74
- store.delete(key);
75
- continue;
76
- }
77
- if (key.startsWith(prefix)) entries.push({
78
- key,
79
- value: JSON.parse(entry.raw)
80
- });
81
- }
82
- return sortAndPaginate(entries, options);
83
- },
84
- async keys(pattern) {
85
- const now = Date.now();
86
- const result = [];
87
- for (const [key, entry] of store) {
88
- if (entry.expiresAt && entry.expiresAt <= now) {
89
- store.delete(key);
90
- continue;
91
- }
92
- if (!pattern || matchGlob(key, pattern)) result.push(key);
93
- }
94
- return result.sort();
95
- }
96
- };
29
+ return pos <= end;
97
30
  }
98
31
  //#endregion
99
- export { MAX_VALUE_SIZE, createMemoryKv, sortAndPaginate };
32
+ export { MAX_VALUE_SIZE, matchGlob, sortAndPaginate };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Vitest custom matchers for AAI testing.
3
+ *
4
+ * Add this to your Vitest setup file to enable `expect(turn).toHaveCalledTool()`:
5
+ *
6
+ * ```ts
7
+ * // vitest.config.ts
8
+ * export default defineConfig({
9
+ * test: { setupFiles: ["@alexkroman1/aai/testing/matchers"] },
10
+ * });
11
+ * ```
12
+ *
13
+ * Or import directly in your test file:
14
+ * ```ts
15
+ * import "@alexkroman1/aai/testing/matchers";
16
+ * ```
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ export {};
@@ -0,0 +1,41 @@
1
+ import { n as TurnResult } from "./testing-MRl3SXsI.js";
2
+ import { expect } from "vitest";
3
+ //#region matchers.ts
4
+ /**
5
+ * Vitest custom matchers for AAI testing.
6
+ *
7
+ * Add this to your Vitest setup file to enable `expect(turn).toHaveCalledTool()`:
8
+ *
9
+ * ```ts
10
+ * // vitest.config.ts
11
+ * export default defineConfig({
12
+ * test: { setupFiles: ["@alexkroman1/aai/testing/matchers"] },
13
+ * });
14
+ * ```
15
+ *
16
+ * Or import directly in your test file:
17
+ * ```ts
18
+ * import "@alexkroman1/aai/testing/matchers";
19
+ * ```
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ expect.extend({ toHaveCalledTool(received, toolName, args) {
24
+ if (!(received instanceof TurnResult)) return {
25
+ pass: false,
26
+ message: () => `expected a TurnResult, got ${typeof received}`,
27
+ actual: received,
28
+ expected: "TurnResult"
29
+ };
30
+ const pass = received.toHaveCalledTool(toolName, args);
31
+ const calledTools = received.toolCalls.map((tc) => tc.toolName);
32
+ const argsHint = args ? ` with args ${JSON.stringify(args)}` : "";
33
+ return {
34
+ pass,
35
+ message: () => pass ? `expected turn NOT to have called tool "${toolName}"${argsHint}, but it was called.\nCalled tools: ${JSON.stringify(calledTools)}` : `expected turn to have called tool "${toolName}"${argsHint}, but it was not.\nCalled tools: ${JSON.stringify(calledTools)}`,
36
+ actual: calledTools,
37
+ expected: toolName
38
+ };
39
+ } });
40
+ //#endregion
41
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * KV-backed memory tools for agent persistent state.
3
+ */
4
+ import { z } from "zod";
5
+ /**
6
+ * Returns a standard set of KV-backed memory tools: `save_memory`,
7
+ * `recall_memory`, `list_memories`, and `forget_memory`.
8
+ *
9
+ * Spread the result into your agent's `tools` record.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { defineAgent, memoryTools } from "aai";
14
+ *
15
+ * export default defineAgent({
16
+ * name: "My Agent",
17
+ * tools: { ...memoryTools() },
18
+ * });
19
+ * ```
20
+ *
21
+ * @returns A record with four tool definitions: `save_memory`, `recall_memory`,
22
+ * `list_memories`, and `forget_memory`.
23
+ * @public
24
+ */
25
+ export declare function memoryTools(): {
26
+ save_memory: import("./types.ts").ToolDef<z.ZodObject<{
27
+ key: z.ZodString;
28
+ value: z.ZodString;
29
+ }, z.core.$strip>, Record<string, unknown>>;
30
+ recall_memory: import("./types.ts").ToolDef<z.ZodObject<{
31
+ key: z.ZodString;
32
+ }, z.core.$strip>, Record<string, unknown>>;
33
+ list_memories: import("./types.ts").ToolDef<z.ZodObject<{
34
+ prefix: z.ZodOptional<z.ZodString>;
35
+ }, z.core.$strip>, Record<string, unknown>>;
36
+ forget_memory: import("./types.ts").ToolDef<z.ZodObject<{
37
+ key: z.ZodString;
38
+ }, z.core.$strip>, Record<string, unknown>>;
39
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Pure middleware runner functions — zero runtime dependencies.
3
+ *
4
+ * This module is intentionally dependency-free so it can be bundled into
5
+ * the secure-exec isolate harness (which has no access to node_modules).
6
+ * Only `import type` statements are allowed here.
7
+ */
8
+ import type { HookContext, Middleware, MiddlewareBlockResult } from "./types.ts";
9
+ /** Result from a middleware tool call interceptor. */
10
+ export type ToolInterceptResult = {
11
+ type: "block";
12
+ reason: string;
13
+ } | {
14
+ type: "result";
15
+ result: string;
16
+ } | {
17
+ type: "args";
18
+ args: Record<string, unknown>;
19
+ } | undefined;
20
+ /**
21
+ * Run all `beforeInput` middleware in order, piping the text through each.
22
+ * Symmetric to {@link runOutputFilters} but for user input.
23
+ */
24
+ export declare function runInputFilters(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<string>;
25
+ /**
26
+ * Run all `beforeTurn` middleware in order. Returns a block result if any
27
+ * middleware blocks the turn, or `undefined` to proceed.
28
+ */
29
+ export declare function runBeforeTurnMiddleware(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<MiddlewareBlockResult | undefined>;
30
+ /**
31
+ * Run all `afterTurn` middleware in reverse order.
32
+ */
33
+ export declare function runAfterTurnMiddleware(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<void>;
34
+ /**
35
+ * Run all `beforeToolCall` middleware in order. Returns a result that
36
+ * may block execution, provide a cached result, or transform args.
37
+ * Returns `undefined` to proceed with normal execution.
38
+ */
39
+ export declare function runToolCallInterceptors(middleware: readonly Middleware[], toolName: string, args: Readonly<Record<string, unknown>>, ctx: HookContext): Promise<ToolInterceptResult>;
40
+ /**
41
+ * Run all `afterToolCall` middleware in reverse order.
42
+ */
43
+ export declare function runAfterToolCallMiddleware(middleware: readonly Middleware[], toolName: string, args: Readonly<Record<string, unknown>>, result: string, ctx: HookContext): Promise<void>;
44
+ /**
45
+ * Run all `beforeOutput` middleware in order, piping the text through each.
46
+ */
47
+ export declare function runOutputFilters(middleware: readonly Middleware[], text: string, ctx: HookContext): Promise<string>;
@@ -0,0 +1,107 @@
1
+ //#region middleware-core.ts
2
+ /**
3
+ * Run all `beforeInput` middleware in order, piping the text through each.
4
+ * Symmetric to {@link runOutputFilters} but for user input.
5
+ */
6
+ async function runInputFilters(middleware, text, ctx) {
7
+ let filtered = text;
8
+ for (const mw of middleware) {
9
+ if (!mw.beforeInput) continue;
10
+ try {
11
+ filtered = await mw.beforeInput(filtered, ctx);
12
+ } catch (err) {
13
+ console.warn("Middleware beforeInput failed:", err);
14
+ }
15
+ }
16
+ return filtered;
17
+ }
18
+ /**
19
+ * Run all `beforeTurn` middleware in order. Returns a block result if any
20
+ * middleware blocks the turn, or `undefined` to proceed.
21
+ */
22
+ async function runBeforeTurnMiddleware(middleware, text, ctx) {
23
+ for (const mw of middleware) {
24
+ if (!mw.beforeTurn) continue;
25
+ try {
26
+ const result = await mw.beforeTurn(text, ctx);
27
+ if (result && "block" in result && result.block) return result;
28
+ } catch (err) {
29
+ console.warn("Middleware beforeTurn failed:", err);
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * Run all `afterTurn` middleware in reverse order.
35
+ */
36
+ async function runAfterTurnMiddleware(middleware, text, ctx) {
37
+ for (let i = middleware.length - 1; i >= 0; i--) {
38
+ const mw = middleware[i];
39
+ if (!mw?.afterTurn) continue;
40
+ try {
41
+ await mw.afterTurn(text, ctx);
42
+ } catch (err) {
43
+ console.warn("Middleware afterTurn failed:", err);
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Run all `beforeToolCall` middleware in order. Returns a result that
49
+ * may block execution, provide a cached result, or transform args.
50
+ * Returns `undefined` to proceed with normal execution.
51
+ */
52
+ async function runToolCallInterceptors(middleware, toolName, args, ctx) {
53
+ let currentArgs = args;
54
+ for (const mw of middleware) {
55
+ if (!mw.beforeToolCall) continue;
56
+ try {
57
+ const result = await mw.beforeToolCall(toolName, currentArgs, ctx);
58
+ if (!result) continue;
59
+ if ("block" in result && result.block) return {
60
+ type: "block",
61
+ reason: result.reason
62
+ };
63
+ if ("result" in result) return {
64
+ type: "result",
65
+ result: result.result
66
+ };
67
+ if ("args" in result) currentArgs = result.args;
68
+ } catch (err) {
69
+ console.warn("Middleware beforeToolCall failed:", err);
70
+ }
71
+ }
72
+ if (currentArgs !== args) return {
73
+ type: "args",
74
+ args: currentArgs
75
+ };
76
+ }
77
+ /**
78
+ * Run all `afterToolCall` middleware in reverse order.
79
+ */
80
+ async function runAfterToolCallMiddleware(middleware, toolName, args, result, ctx) {
81
+ for (let i = middleware.length - 1; i >= 0; i--) {
82
+ const mw = middleware[i];
83
+ if (!mw?.afterToolCall) continue;
84
+ try {
85
+ await mw.afterToolCall(toolName, args, result, ctx);
86
+ } catch (err) {
87
+ console.warn("Middleware afterToolCall failed:", err);
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Run all `beforeOutput` middleware in order, piping the text through each.
93
+ */
94
+ async function runOutputFilters(middleware, text, ctx) {
95
+ let filtered = text;
96
+ for (const mw of middleware) {
97
+ if (!mw.beforeOutput) continue;
98
+ try {
99
+ filtered = await mw.beforeOutput(filtered, ctx);
100
+ } catch (err) {
101
+ console.warn("Middleware beforeOutput failed:", err);
102
+ }
103
+ }
104
+ return filtered;
105
+ }
106
+ //#endregion
107
+ export { runAfterToolCallMiddleware, runAfterTurnMiddleware, runBeforeTurnMiddleware, runInputFilters, runOutputFilters, runToolCallInterceptors };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Middleware runner — executes middleware chains for turns, tool calls,
3
+ * and output filtering.
4
+ *
5
+ * Pure runner logic lives in middleware-core.ts (isolate-safe, zero deps).
6
+ * This module re-exports it and adds the HookInvoker interface.
7
+ */
8
+ import type { StepInfo } from "./types.ts";
9
+ export { runAfterToolCallMiddleware, runAfterTurnMiddleware, runBeforeTurnMiddleware, runInputFilters, runOutputFilters, runToolCallInterceptors, type ToolInterceptResult, } from "./middleware-core.ts";
10
+ /** Generic interface for invoking agent lifecycle hooks, including middleware. */
11
+ export type HookInvoker = {
12
+ onConnect(sessionId: string, timeoutMs?: number): Promise<void>;
13
+ onDisconnect(sessionId: string, timeoutMs?: number): Promise<void>;
14
+ onTurn(sessionId: string, text: string, timeoutMs?: number): Promise<void>;
15
+ onError(sessionId: string, error: {
16
+ message: string;
17
+ }, timeoutMs?: number): Promise<void>;
18
+ onStep(sessionId: string, step: StepInfo, timeoutMs?: number): Promise<void>;
19
+ resolveTurnConfig(sid: string, ms?: number): Promise<{
20
+ maxSteps?: number;
21
+ } | null>;
22
+ filterInput?(sid: string, text: string, ms?: number): Promise<string>;
23
+ beforeTurn?(sid: string, text: string, ms?: number): Promise<string | undefined>;
24
+ afterTurn?(sid: string, text: string, ms?: number): Promise<void>;
25
+ interceptToolCall?(sid: string, tool: string, args: Readonly<Record<string, unknown>>, ms?: number): Promise<{
26
+ type: "block";
27
+ reason: string;
28
+ } | {
29
+ type: "result";
30
+ result: string;
31
+ } | {
32
+ type: "args";
33
+ args: Record<string, unknown>;
34
+ } | undefined>;
35
+ afterToolCall?(sid: string, tool: string, args: Readonly<Record<string, unknown>>, result: string, ms?: number): Promise<void>;
36
+ filterOutput?(sid: string, text: string, ms?: number): Promise<string>;
37
+ };