@alexkroman1/aai 0.10.2 → 0.10.4

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 (60) hide show
  1. package/dist/_internal-types.d.ts +8 -1
  2. package/dist/_runtime-conformance.d.ts +64 -0
  3. package/dist/_test-utils.d.ts +70 -0
  4. package/dist/_utils.d.ts +1 -8
  5. package/dist/_utils.js +1 -13
  6. package/dist/builtin-tools.d.ts +1 -5
  7. package/dist/constants-BbAOvKl_.js +47 -0
  8. package/dist/constants.d.ts +44 -0
  9. package/dist/direct-executor-BfHrDdPL.js +1589 -0
  10. package/dist/direct-executor.d.ts +90 -31
  11. package/dist/hooks.d.ts +44 -0
  12. package/dist/hooks.js +58 -0
  13. package/dist/index.d.ts +1 -2
  14. package/dist/index.js +2 -2
  15. package/dist/internal.d.ts +19 -0
  16. package/dist/internal.js +209 -0
  17. package/dist/kv.d.ts +1 -1
  18. package/dist/kv.js +5 -4
  19. package/dist/matchers.js +1 -1
  20. package/dist/protocol.d.ts +3 -29
  21. package/dist/protocol.js +2 -24
  22. package/dist/server.d.ts +25 -38
  23. package/dist/server.js +114 -138
  24. package/dist/session.d.ts +65 -44
  25. package/dist/{testing-MRl3SXsI.js → testing-BonJtfHJ.js} +26 -46
  26. package/dist/testing.d.ts +9 -14
  27. package/dist/testing.js +2 -2
  28. package/dist/types.d.ts +24 -226
  29. package/dist/types.js +6 -22
  30. package/dist/types.test-d.d.ts +7 -0
  31. package/dist/unstorage-kv.d.ts +33 -0
  32. package/dist/vite-plugin.d.ts +15 -0
  33. package/dist/vite-plugin.js +82 -0
  34. package/dist/ws-handler.d.ts +1 -2
  35. package/package.json +29 -84
  36. package/dist/_internal-types.js +0 -61
  37. package/dist/_session-ctx.d.ts +0 -73
  38. package/dist/_session-otel.d.ts +0 -43
  39. package/dist/_session-persist.d.ts +0 -30
  40. package/dist/_ssrf.d.ts +0 -30
  41. package/dist/_ssrf.js +0 -123
  42. package/dist/direct-executor-Ca0wt5H0.js +0 -572
  43. package/dist/middleware-core.d.ts +0 -47
  44. package/dist/middleware-core.js +0 -107
  45. package/dist/middleware.d.ts +0 -37
  46. package/dist/runtime.js +0 -53
  47. package/dist/s2s.js +0 -272
  48. package/dist/session-BkN9u0ni.js +0 -683
  49. package/dist/session.js +0 -2
  50. package/dist/sqlite-kv.d.ts +0 -34
  51. package/dist/sqlite-kv.js +0 -133
  52. package/dist/sqlite-vector.d.ts +0 -58
  53. package/dist/sqlite-vector.js +0 -149
  54. package/dist/telemetry.d.ts +0 -49
  55. package/dist/telemetry.js +0 -95
  56. package/dist/vector.d.ts +0 -85
  57. package/dist/vector.js +0 -49
  58. package/dist/worker-entry.d.ts +0 -47
  59. package/dist/worker-entry.js +0 -70
  60. package/dist/ws-handler.js +0 -207
@@ -1,34 +0,0 @@
1
- /**
2
- * SQLite-backed key-value storage for local development.
3
- *
4
- * Persists data across restarts using a local SQLite database file.
5
- * Uses `node:sqlite` (built into Node 22+) — no native dependencies.
6
- * Drop-in replacement for the in-memory KV store.
7
- */
8
- import type { Kv } from "./kv.ts";
9
- /**
10
- * Options for creating a SQLite-backed KV store.
11
- */
12
- export type SqliteKvOptions = {
13
- /** Path to the SQLite database file. Defaults to `.aai/local.db`. */
14
- path?: string;
15
- };
16
- /**
17
- * Create a SQLite-backed KV store for local development.
18
- *
19
- * Data persists to a local SQLite file (default: `.aai/local.db`).
20
- * TTL expiration is enforced on reads and periodically cleaned up.
21
- *
22
- * @param options - Optional configuration. See {@link SqliteKvOptions}.
23
- * @returns A {@link Kv} instance backed by SQLite.
24
- *
25
- * @example
26
- * ```ts
27
- * import { createSqliteKv } from "@alexkroman1/aai/sqlite-kv";
28
- *
29
- * const kv = createSqliteKv();
30
- * await kv.set("greeting", "hello");
31
- * const value = await kv.get<string>("greeting"); // "hello"
32
- * ```
33
- */
34
- export declare function createSqliteKv(options?: SqliteKvOptions): Kv;
package/dist/sqlite-kv.js DELETED
@@ -1,133 +0,0 @@
1
- import { MAX_VALUE_SIZE, matchGlob, sortAndPaginate } from "./kv.js";
2
- import { DatabaseSync } from "node:sqlite";
3
- //#region sqlite-kv.ts
4
- /**
5
- * SQLite-backed key-value storage for local development.
6
- *
7
- * Persists data across restarts using a local SQLite database file.
8
- * Uses `node:sqlite` (built into Node 22+) — no native dependencies.
9
- * Drop-in replacement for the in-memory KV store.
10
- */
11
- /**
12
- * Create a SQLite-backed KV store for local development.
13
- *
14
- * Data persists to a local SQLite file (default: `.aai/local.db`).
15
- * TTL expiration is enforced on reads and periodically cleaned up.
16
- *
17
- * @param options - Optional configuration. See {@link SqliteKvOptions}.
18
- * @returns A {@link Kv} instance backed by SQLite.
19
- *
20
- * @example
21
- * ```ts
22
- * import { createSqliteKv } from "@alexkroman1/aai/sqlite-kv";
23
- *
24
- * const kv = createSqliteKv();
25
- * await kv.set("greeting", "hello");
26
- * const value = await kv.get<string>("greeting"); // "hello"
27
- * ```
28
- */
29
- function createSqliteKv(options) {
30
- const db = new DatabaseSync(options?.path ?? ".aai/local.db");
31
- db.exec("PRAGMA journal_mode = WAL");
32
- db.exec(`
33
- CREATE TABLE IF NOT EXISTS kv (
34
- key TEXT PRIMARY KEY,
35
- value TEXT NOT NULL,
36
- expires_at INTEGER
37
- )
38
- `);
39
- db.exec(`
40
- CREATE INDEX IF NOT EXISTS idx_kv_expires_at ON kv(expires_at)
41
- WHERE expires_at IS NOT NULL
42
- `);
43
- const stmtGet = db.prepare("SELECT value, expires_at FROM kv WHERE key = ?");
44
- const stmtUpsert = db.prepare("INSERT INTO kv (key, value, expires_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at");
45
- const stmtDelete = db.prepare("DELETE FROM kv WHERE key = ?");
46
- const stmtDeleteExpired = db.prepare("DELETE FROM kv WHERE expires_at IS NOT NULL AND expires_at <= ?");
47
- const stmtListPrefix = db.prepare("SELECT key, value FROM kv WHERE key >= ? AND key < ? AND (expires_at IS NULL OR expires_at > ?)");
48
- const stmtListAll = db.prepare("SELECT key, value FROM kv WHERE expires_at IS NULL OR expires_at > ?");
49
- const stmtKeysAll = db.prepare("SELECT key FROM kv WHERE expires_at IS NULL OR expires_at > ?");
50
- const stmtKeysPrefix = db.prepare("SELECT key FROM kv WHERE key >= ? AND key < ? AND (expires_at IS NULL OR expires_at > ?)");
51
- /** Compute the exclusive upper bound for a prefix scan. */
52
- function prefixUpperBound(prefix) {
53
- if (prefix === "") return "￿";
54
- const last = prefix.charCodeAt(prefix.length - 1);
55
- return prefix.slice(0, -1) + String.fromCharCode(last + 1);
56
- }
57
- const cleanupInterval = setInterval(() => {
58
- stmtDeleteExpired.run(Date.now());
59
- }, 6e4);
60
- if (cleanupInterval.unref) cleanupInterval.unref();
61
- return {
62
- close() {
63
- clearInterval(cleanupInterval);
64
- db.close();
65
- },
66
- get(key) {
67
- const now = Date.now();
68
- const row = stmtGet.get(key);
69
- if (!row) return Promise.resolve(null);
70
- if (row.expires_at !== null && row.expires_at <= now) {
71
- stmtDelete.run(key);
72
- return Promise.resolve(null);
73
- }
74
- return Promise.resolve(JSON.parse(row.value));
75
- },
76
- set(key, value, setOptions) {
77
- try {
78
- const raw = JSON.stringify(value);
79
- if (raw.length > 65536) return Promise.reject(/* @__PURE__ */ new Error(`Value exceeds max size of ${MAX_VALUE_SIZE} bytes`));
80
- const expireIn = setOptions?.expireIn;
81
- const expiresAt = expireIn && expireIn > 0 ? Date.now() + expireIn : null;
82
- stmtUpsert.run(key, raw, expiresAt);
83
- return Promise.resolve();
84
- } catch (err) {
85
- return Promise.reject(err);
86
- }
87
- },
88
- delete(keys) {
89
- const keyArray = Array.isArray(keys) ? keys : [keys];
90
- for (const k of keyArray) stmtDelete.run(k);
91
- return Promise.resolve();
92
- },
93
- list(prefix, listOptions) {
94
- const now = Date.now();
95
- let rows;
96
- if (prefix === "") rows = stmtListAll.all(now);
97
- else {
98
- const upper = prefixUpperBound(prefix);
99
- rows = stmtListPrefix.all(prefix, upper, now);
100
- }
101
- const entries = rows.map((row) => ({
102
- key: row.key,
103
- value: JSON.parse(row.value)
104
- }));
105
- return Promise.resolve(sortAndPaginate(entries, listOptions));
106
- },
107
- keys(pattern) {
108
- const now = Date.now();
109
- const isGlob = pattern?.includes("*");
110
- if (!pattern) {
111
- const keys = stmtKeysAll.all(now).map((r) => r.key);
112
- return Promise.resolve(keys.sort((a, b) => a.localeCompare(b)));
113
- }
114
- if (isGlob) {
115
- const starIdx = pattern.indexOf("*");
116
- const prefix = pattern.slice(0, starIdx);
117
- let rows;
118
- if (prefix === "") rows = stmtKeysAll.all(now);
119
- else {
120
- const upper = prefixUpperBound(prefix);
121
- rows = stmtKeysPrefix.all(prefix, upper, now);
122
- }
123
- const keys = rows.filter((r) => matchGlob(r.key, pattern)).map((r) => r.key);
124
- return Promise.resolve(keys.sort((a, b) => a.localeCompare(b)));
125
- }
126
- const upper = prefixUpperBound(pattern);
127
- const keys = stmtKeysPrefix.all(pattern, upper, now).map((r) => r.key);
128
- return Promise.resolve(keys.sort((a, b) => a.localeCompare(b)));
129
- }
130
- };
131
- }
132
- //#endregion
133
- export { createSqliteKv };
@@ -1,58 +0,0 @@
1
- /**
2
- * SQLite-backed vector store with local embeddings.
3
- *
4
- * Persists data across restarts using a local SQLite database file.
5
- * Uses brute-force cosine similarity over `node:sqlite` — no native
6
- * extensions required. Fast enough for local dev (sub-ms for <10k vectors).
7
- * Embeddings are computed locally via `all-MiniLM-L6-v2` (384 dims) —
8
- * no external API key required. The model is downloaded on first use
9
- * (~86 MB) and cached in `.aai/models/`.
10
- */
11
- import type { VectorStore } from "./vector.ts";
12
- /** Function that converts text into an embedding vector. */
13
- export type EmbedFn = (text: string) => Promise<number[]>;
14
- /**
15
- * Options for creating a SQLite-vec backed vector store.
16
- */
17
- export type SqliteVecVectorStoreOptions = {
18
- /** Path to the SQLite database file. Defaults to `.aai/vectors.db`. */
19
- path?: string;
20
- /** Custom embedding function. Defaults to local `all-MiniLM-L6-v2` model. */
21
- embedFn?: EmbedFn;
22
- /** Embedding dimensions. Must match the embedFn output. Defaults to 384. */
23
- dimensions?: number;
24
- /** Directory for caching downloaded models. Defaults to `.aai/models`. */
25
- modelCacheDir?: string;
26
- };
27
- /**
28
- * Create a deterministic hash-based embedding function for testing.
29
- *
30
- * Produces repeatable vectors where similar text yields similar embeddings.
31
- * Not suitable for production — use the default local model instead.
32
- *
33
- * @param dimensions - Vector dimensions (default: 384).
34
- */
35
- export declare function createTestEmbedFn(dimensions?: number): EmbedFn;
36
- /**
37
- * Create a SQLite-backed vector store with local embeddings.
38
- *
39
- * Data persists to a local SQLite file (default: `.aai/vectors.db`).
40
- * Embeddings are computed locally using `all-MiniLM-L6-v2` by default —
41
- * no API key required. The model auto-downloads on first use (~86 MB).
42
- *
43
- * Vector search uses brute-force cosine similarity over all stored
44
- * embeddings. This is fast for local dev workloads (<10k vectors).
45
- *
46
- * @param options - See {@link SqliteVecVectorStoreOptions}.
47
- * @returns A {@link VectorStore} instance.
48
- *
49
- * @example
50
- * ```ts
51
- * import { createSqliteVectorStore } from "@alexkroman1/aai/sqlite-vector";
52
- *
53
- * const vector = createSqliteVectorStore();
54
- * await vector.upsert("doc-1", "The capital of France is Paris.");
55
- * const results = await vector.query("France capital");
56
- * ```
57
- */
58
- export declare function createSqliteVectorStore(options?: SqliteVecVectorStoreOptions): VectorStore;
@@ -1,149 +0,0 @@
1
- import { DatabaseSync } from "node:sqlite";
2
- //#region sqlite-vector.ts
3
- /**
4
- * SQLite-backed vector store with local embeddings.
5
- *
6
- * Persists data across restarts using a local SQLite database file.
7
- * Uses brute-force cosine similarity over `node:sqlite` — no native
8
- * extensions required. Fast enough for local dev (sub-ms for <10k vectors).
9
- * Embeddings are computed locally via `all-MiniLM-L6-v2` (384 dims) —
10
- * no external API key required. The model is downloaded on first use
11
- * (~86 MB) and cached in `.aai/models/`.
12
- */
13
- const DEFAULT_DIMENSIONS = 384;
14
- const DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
15
- /**
16
- * Create a local embedding function using `all-MiniLM-L6-v2`.
17
- *
18
- * The model is downloaded on first use (~86 MB) and cached locally.
19
- * Subsequent calls load from cache in ~90ms. Each embedding takes <2ms.
20
- */
21
- function createLocalEmbedFn(cacheDir) {
22
- let pipelinePromise = null;
23
- async function getPipeline() {
24
- if (!pipelinePromise) pipelinePromise = (async () => {
25
- const { pipeline, env } = await import("@huggingface/transformers");
26
- env.cacheDir = cacheDir;
27
- return pipeline("feature-extraction", DEFAULT_MODEL);
28
- })();
29
- return pipelinePromise;
30
- }
31
- return async (text) => {
32
- const output = await (await getPipeline())(text, {
33
- pooling: "mean",
34
- normalize: true
35
- });
36
- return Array.from(output.data);
37
- };
38
- }
39
- /**
40
- * Create a deterministic hash-based embedding function for testing.
41
- *
42
- * Produces repeatable vectors where similar text yields similar embeddings.
43
- * Not suitable for production — use the default local model instead.
44
- *
45
- * @param dimensions - Vector dimensions (default: 384).
46
- */
47
- function createTestEmbedFn(dimensions = DEFAULT_DIMENSIONS) {
48
- return async (text) => {
49
- const vec = new Float32Array(dimensions);
50
- const words = text.toLowerCase().split(/\s+/).filter(Boolean);
51
- for (const word of words) {
52
- let hash = 0;
53
- for (let i = 0; i < word.length; i++) hash = (hash << 5) - hash + word.charCodeAt(i) | 0;
54
- for (let i = 0; i < 8; i++) {
55
- const idx = Math.abs((hash + i * 31337) % dimensions);
56
- vec[idx] = (vec[idx] ?? 0) + 1;
57
- }
58
- }
59
- let norm = 0;
60
- for (let i = 0; i < dimensions; i++) norm += (vec[i] ?? 0) * (vec[i] ?? 0);
61
- norm = Math.sqrt(norm) || 1;
62
- return Array.from(vec, (v) => v / norm);
63
- };
64
- }
65
- /** Cosine similarity between two vectors stored as Buffers of float32. */
66
- function cosineSimilarity(a, b) {
67
- const fa = new Float32Array(a.buffer, a.byteOffset, a.byteLength / 4);
68
- const fb = new Float32Array(b.buffer, b.byteOffset, b.byteLength / 4);
69
- let dot = 0;
70
- let normA = 0;
71
- let normB = 0;
72
- for (let i = 0; i < fa.length; i++) {
73
- const ai = fa[i] ?? 0;
74
- const bi = fb[i] ?? 0;
75
- dot += ai * bi;
76
- normA += ai * ai;
77
- normB += bi * bi;
78
- }
79
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
80
- return denom === 0 ? 0 : dot / denom;
81
- }
82
- /**
83
- * Create a SQLite-backed vector store with local embeddings.
84
- *
85
- * Data persists to a local SQLite file (default: `.aai/vectors.db`).
86
- * Embeddings are computed locally using `all-MiniLM-L6-v2` by default —
87
- * no API key required. The model auto-downloads on first use (~86 MB).
88
- *
89
- * Vector search uses brute-force cosine similarity over all stored
90
- * embeddings. This is fast for local dev workloads (<10k vectors).
91
- *
92
- * @param options - See {@link SqliteVecVectorStoreOptions}.
93
- * @returns A {@link VectorStore} instance.
94
- *
95
- * @example
96
- * ```ts
97
- * import { createSqliteVectorStore } from "@alexkroman1/aai/sqlite-vector";
98
- *
99
- * const vector = createSqliteVectorStore();
100
- * await vector.upsert("doc-1", "The capital of France is Paris.");
101
- * const results = await vector.query("France capital");
102
- * ```
103
- */
104
- function createSqliteVectorStore(options) {
105
- const dbPath = options?.path ?? ".aai/vectors.db";
106
- const cacheDir = options?.modelCacheDir ?? ".aai/models";
107
- const embedFn = options?.embedFn ?? createLocalEmbedFn(cacheDir);
108
- const db = new DatabaseSync(dbPath);
109
- db.exec("PRAGMA journal_mode = WAL");
110
- db.exec(`
111
- CREATE TABLE IF NOT EXISTS vectors (
112
- id TEXT PRIMARY KEY,
113
- data TEXT NOT NULL,
114
- metadata TEXT NOT NULL DEFAULT '',
115
- embedding BLOB NOT NULL
116
- )
117
- `);
118
- const stmtUpsert = db.prepare("INSERT OR REPLACE INTO vectors (id, data, metadata, embedding) VALUES (?, ?, ?, ?)");
119
- const stmtDelete = db.prepare("DELETE FROM vectors WHERE id = ?");
120
- const stmtAll = db.prepare("SELECT id, data, metadata, embedding FROM vectors");
121
- return {
122
- async upsert(id, data, metadata) {
123
- const vector = await embedFn(data);
124
- const embedding = Buffer.from(new Float32Array(vector).buffer);
125
- const metaJson = metadata ? JSON.stringify(metadata) : "";
126
- stmtUpsert.run(id, data, metaJson, embedding);
127
- },
128
- async query(text, queryOptions) {
129
- const topK = queryOptions?.topK ?? 10;
130
- if (!text.trim()) return [];
131
- const queryVec = await embedFn(text);
132
- const queryBuf = Buffer.from(new Float32Array(queryVec).buffer);
133
- const scored = stmtAll.all().map((row) => ({
134
- id: row.id,
135
- score: cosineSimilarity(queryBuf, row.embedding),
136
- data: row.data,
137
- metadata: row.metadata && row.metadata !== "" ? JSON.parse(row.metadata) : void 0
138
- }));
139
- scored.sort((a, b) => b.score - a.score);
140
- return scored.slice(0, topK);
141
- },
142
- async delete(ids) {
143
- const idArray = Array.isArray(ids) ? ids : [ids];
144
- for (const id of idArray) stmtDelete.run(id);
145
- }
146
- };
147
- }
148
- //#endregion
149
- export { createSqliteVectorStore, createTestEmbedFn };
@@ -1,49 +0,0 @@
1
- /**
2
- * OpenTelemetry instrumentation helpers for the AAI SDK.
3
- *
4
- * Uses `@opentelemetry/api` only — consumers bring their own SDK and
5
- * exporters. When no SDK is configured the API returns no-op instances,
6
- * so the overhead in uninstrumented environments is negligible.
7
- *
8
- * Provides:
9
- * - `tracer` — a pre-scoped `Tracer` for creating spans
10
- * - `meter` — a pre-scoped `Meter` for recording metrics
11
- * - Pre-built counters, histograms, and up/down counters covering the
12
- * STT → LLM → TTS pipeline
13
- */
14
- import { type Meter, type Span, type Tracer } from "@opentelemetry/api";
15
- /** Tracer scoped to the AAI SDK. */
16
- export declare const tracer: Tracer;
17
- /** Meter scoped to the AAI SDK. */
18
- export declare const meter: Meter;
19
- /** Total sessions opened. */
20
- export declare const sessionCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
21
- /** Currently active sessions. */
22
- export declare const activeSessionsUpDown: import("@opentelemetry/api").UpDownCounter<import("@opentelemetry/api").Attributes>;
23
- /** Total user turns (speech → transcript). */
24
- export declare const turnCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
25
- /** Total tool calls executed. */
26
- export declare const toolCallCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
27
- /** Tool call execution duration in seconds. */
28
- export declare const toolCallDuration: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
29
- /** Total tool call errors. */
30
- export declare const toolCallErrorCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
31
- /** S2S WebSocket connection duration in seconds. */
32
- export declare const s2sConnectionDuration: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
33
- /** Total S2S errors. */
34
- export declare const s2sErrorCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
35
- /** Number of agentic loop steps (tool calls) per completed turn. */
36
- export declare const turnStepsHistogram: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
37
- /** Total barge-in (reply interrupted) events. */
38
- export declare const bargeInCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
39
- /** Messages silently dropped because the WebSocket was closed. */
40
- export declare const wsSendDroppedCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
41
- /** Sessions closed due to S2S idle timeout. */
42
- export declare const idleTimeoutCounter: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
43
- /**
44
- * Run `fn` inside a new span. The span is automatically ended and its
45
- * status set based on whether `fn` throws.
46
- */
47
- export declare function withSpan<T>(name: string, fn: (span: Span) => T): T;
48
- export type { Meter, Span, Tracer } from "@opentelemetry/api";
49
- export { context, metrics, SpanStatusCode, trace } from "@opentelemetry/api";
package/dist/telemetry.js DELETED
@@ -1,95 +0,0 @@
1
- import { createRequire } from "node:module";
2
- import { SpanStatusCode, SpanStatusCode as SpanStatusCode$1, context, metrics, metrics as metrics$1, trace, trace as trace$1 } from "@opentelemetry/api";
3
- //#region telemetry.ts
4
- /**
5
- * OpenTelemetry instrumentation helpers for the AAI SDK.
6
- *
7
- * Uses `@opentelemetry/api` only — consumers bring their own SDK and
8
- * exporters. When no SDK is configured the API returns no-op instances,
9
- * so the overhead in uninstrumented environments is negligible.
10
- *
11
- * Provides:
12
- * - `tracer` — a pre-scoped `Tracer` for creating spans
13
- * - `meter` — a pre-scoped `Meter` for recording metrics
14
- * - Pre-built counters, histograms, and up/down counters covering the
15
- * STT → LLM → TTS pipeline
16
- */
17
- const SCOPE = "aai";
18
- const _require = createRequire(import.meta.url);
19
- let VERSION = "0.0.0";
20
- try {
21
- VERSION = _require("./package.json").version;
22
- } catch {
23
- VERSION = _require("../package.json").version;
24
- }
25
- /** Tracer scoped to the AAI SDK. */
26
- const tracer = trace$1.getTracer(SCOPE, VERSION);
27
- /** Meter scoped to the AAI SDK. */
28
- const meter = metrics$1.getMeter(SCOPE, VERSION);
29
- /** Total sessions opened. */
30
- const sessionCounter = meter.createCounter("aai.session.count", { description: "Total voice sessions opened" });
31
- /** Currently active sessions. */
32
- const activeSessionsUpDown = meter.createUpDownCounter("aai.session.active", { description: "Currently active voice sessions" });
33
- /** Total user turns (speech → transcript). */
34
- const turnCounter = meter.createCounter("aai.turn.count", { description: "Total user turns" });
35
- /** Total tool calls executed. */
36
- const toolCallCounter = meter.createCounter("aai.tool.call.count", { description: "Total tool calls executed" });
37
- /** Tool call execution duration in seconds. */
38
- const toolCallDuration = meter.createHistogram("aai.tool.call.duration", {
39
- description: "Tool call execution duration in seconds",
40
- unit: "s"
41
- });
42
- /** Total tool call errors. */
43
- const toolCallErrorCounter = meter.createCounter("aai.tool.call.error.count", { description: "Total tool call errors" });
44
- /** S2S WebSocket connection duration in seconds. */
45
- const s2sConnectionDuration = meter.createHistogram("aai.s2s.connection.duration", {
46
- description: "S2S WebSocket connection duration in seconds",
47
- unit: "s"
48
- });
49
- /** Total S2S errors. */
50
- const s2sErrorCounter = meter.createCounter("aai.s2s.error.count", { description: "Total S2S errors" });
51
- /** Number of agentic loop steps (tool calls) per completed turn. */
52
- const turnStepsHistogram = meter.createHistogram("aai.turn.steps", { description: "Number of agentic loop steps per completed turn" });
53
- /** Total barge-in (reply interrupted) events. */
54
- const bargeInCounter = meter.createCounter("aai.turn.bargein.count", { description: "Total barge-in (reply interrupted) events" });
55
- /** Messages silently dropped because the WebSocket was closed. */
56
- const wsSendDroppedCounter = meter.createCounter("aai.ws.send_dropped", { description: "Messages silently dropped because the WebSocket was closed" });
57
- /** Sessions closed due to S2S idle timeout. */
58
- const idleTimeoutCounter = meter.createCounter("aai.session.idle.timeout.count", { description: "Sessions closed due to S2S idle timeout" });
59
- /**
60
- * Run `fn` inside a new span. The span is automatically ended and its
61
- * status set based on whether `fn` throws.
62
- */
63
- function withSpan(name, fn) {
64
- return tracer.startActiveSpan(name, (span) => {
65
- try {
66
- const result = fn(span);
67
- if (result instanceof Promise) return result.then((v) => {
68
- span.setStatus({ code: SpanStatusCode$1.OK });
69
- span.end();
70
- return v;
71
- }).catch((err) => {
72
- span.setStatus({
73
- code: SpanStatusCode$1.ERROR,
74
- message: err instanceof Error ? err.message : String(err)
75
- });
76
- span.recordException(err instanceof Error ? err : new Error(String(err)));
77
- span.end();
78
- throw err;
79
- });
80
- span.setStatus({ code: SpanStatusCode$1.OK });
81
- span.end();
82
- return result;
83
- } catch (err) {
84
- span.setStatus({
85
- code: SpanStatusCode$1.ERROR,
86
- message: err instanceof Error ? err.message : String(err)
87
- });
88
- span.recordException(err instanceof Error ? err : new Error(String(err)));
89
- span.end();
90
- throw err;
91
- }
92
- });
93
- }
94
- //#endregion
95
- export { SpanStatusCode, activeSessionsUpDown, bargeInCounter, context, idleTimeoutCounter, meter, metrics, s2sConnectionDuration, s2sErrorCounter, sessionCounter, toolCallCounter, toolCallDuration, toolCallErrorCounter, trace, tracer, turnCounter, turnStepsHistogram, withSpan, wsSendDroppedCounter };
package/dist/vector.d.ts DELETED
@@ -1,85 +0,0 @@
1
- /**
2
- * Vector store interface.
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;
18
- /**
19
- * A single vector search result entry.
20
- *
21
- * @public
22
- */
23
- export type VectorEntry = {
24
- /** The unique identifier for this entry. */
25
- id: string;
26
- /** Similarity score (higher = more similar). */
27
- score: number;
28
- /** The original text data stored with this entry. */
29
- data?: string | undefined;
30
- /** Arbitrary metadata stored with this entry. */
31
- metadata?: Record<string, unknown> | undefined;
32
- };
33
- /**
34
- * Async vector store interface used by agents.
35
- *
36
- * Agents access the vector store via `ToolContext.vector` or
37
- * `HookContext.vector`. Backed by Upstash Vector with built-in
38
- * embeddings — raw text is sent and vectorized server-side.
39
- *
40
- * @example
41
- * ```ts
42
- * // Inside a tool execute function:
43
- * const myTool = {
44
- * description: "Search knowledge base",
45
- * execute: async (_args: unknown, ctx: { vector: VectorStore }) => {
46
- * await ctx.vector.upsert("doc-1", "The capital of France is Paris.");
47
- * const results = await ctx.vector.query("What is the capital of France?");
48
- * return results;
49
- * },
50
- * };
51
- * ```
52
- *
53
- * @public
54
- */
55
- export type VectorStore = {
56
- /**
57
- * Upsert a text entry into the vector store.
58
- *
59
- * The text is automatically embedded by the server's vector database.
60
- *
61
- * @param id - Unique identifier for this entry.
62
- * @param data - The text content to store and embed.
63
- * @param metadata - Optional metadata to store alongside the vector.
64
- */
65
- upsert(id: string, data: string, metadata?: Record<string, unknown>): Promise<void>;
66
- /**
67
- * Query the vector store with a text string.
68
- *
69
- * Returns the most similar entries ranked by score.
70
- *
71
- * @param text - The query text to search for.
72
- * @param options - Optional query parameters. `topK` sets the maximum number of results (default: 10). `filter` is a metadata filter expression.
73
- * @returns An array of matching {@link VectorEntry} objects.
74
- */
75
- query(text: string, options?: {
76
- topK?: number;
77
- filter?: string;
78
- }): Promise<VectorEntry[]>;
79
- /**
80
- * Delete entries by ID.
81
- *
82
- * @param ids - A single ID or array of IDs to delete.
83
- */
84
- delete(ids: string | string[]): Promise<void>;
85
- };
package/dist/vector.js DELETED
@@ -1,49 +0,0 @@
1
- //#region vector.ts
2
- /**
3
- * Vector store interface.
4
- */
5
- /**
6
- * Maximum allowed length for a vector filter expression.
7
- * @internal
8
- */
9
- const MAX_FILTER_LENGTH = 1e3;
10
- /**
11
- * SQL/query keywords that must not appear in filter expressions.
12
- * Checked case-insensitively as whole words (word-boundary match).
13
- * @internal
14
- */
15
- const DANGEROUS_KEYWORDS = /\b(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC|EXECUTE|UNION|INTO|TRUNCATE|GRANT|REVOKE|CALL)\b/i;
16
- /**
17
- * Patterns that indicate injection attempts in filter strings.
18
- * @internal
19
- */
20
- const DANGEROUS_PATTERNS = [
21
- /;/,
22
- /--/,
23
- /\/\*/,
24
- /\*\//,
25
- /\0/
26
- ];
27
- /**
28
- * Validate a vector filter expression to prevent injection attacks.
29
- *
30
- * Rejects filters containing SQL keywords (SELECT, DROP, etc.),
31
- * statement terminators, comments, and null bytes. Enforces a
32
- * maximum length of 1000 characters.
33
- *
34
- * @param filter - The raw filter string from user input.
35
- * @returns The validated filter string (trimmed).
36
- * @throws Error if the filter contains dangerous patterns.
37
- *
38
- * @public
39
- */
40
- function validateVectorFilter(filter) {
41
- const trimmed = filter.trim();
42
- if (trimmed.length === 0) throw new Error("Vector filter must not be empty");
43
- if (trimmed.length > MAX_FILTER_LENGTH) throw new Error(`Vector filter exceeds maximum length of ${MAX_FILTER_LENGTH} characters`);
44
- if (DANGEROUS_KEYWORDS.test(trimmed)) throw new Error("Vector filter contains disallowed SQL keyword");
45
- for (const pattern of DANGEROUS_PATTERNS) if (pattern.test(trimmed)) throw new Error("Vector filter contains disallowed characters");
46
- return trimmed;
47
- }
48
- //#endregion
49
- export { validateVectorFilter };