@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.
Files changed (74) hide show
  1. package/dist/_internal-types.d.ts +8 -1
  2. package/dist/_run-code.d.ts +16 -12
  3. package/dist/_runtime-conformance.d.ts +55 -0
  4. package/dist/_test-utils.d.ts +73 -0
  5. package/dist/_utils.d.ts +0 -19
  6. package/dist/_utils.js +28 -2
  7. package/dist/builtin-tools.d.ts +1 -5
  8. package/dist/constants-CwotjpJR.js +45 -0
  9. package/dist/constants.d.ts +42 -0
  10. package/dist/direct-executor-DAGCZOAN.js +1530 -0
  11. package/dist/direct-executor.d.ts +90 -31
  12. package/dist/hooks.d.ts +44 -0
  13. package/dist/hooks.js +58 -0
  14. package/dist/index.d.ts +1 -2
  15. package/dist/index.js +2 -2
  16. package/dist/internal.d.ts +19 -0
  17. package/dist/internal.js +164 -0
  18. package/dist/kv.d.ts +1 -1
  19. package/dist/kv.js +32 -1
  20. package/dist/matchers.js +1 -1
  21. package/dist/protocol.d.ts +3 -29
  22. package/dist/protocol.js +140 -2
  23. package/dist/server.d.ts +27 -40
  24. package/dist/server.js +117 -145
  25. package/dist/session.d.ts +65 -44
  26. package/dist/{testing-BbitshLb.js → testing-Dmx-dudh.js} +39 -43
  27. package/dist/testing.d.ts +9 -14
  28. package/dist/testing.js +2 -2
  29. package/dist/types.d.ts +24 -226
  30. package/dist/types.js +176 -2
  31. package/dist/types.test-d.d.ts +7 -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 +34 -95
  36. package/dist/_embeddings.d.ts +0 -31
  37. package/dist/_internal-types-IfPcaJd5.js +0 -61
  38. package/dist/_internal-types.js +0 -2
  39. package/dist/_session-ctx.d.ts +0 -73
  40. package/dist/_session-otel.d.ts +0 -43
  41. package/dist/_session-persist.d.ts +0 -30
  42. package/dist/_ssrf-DCp_27V4.js +0 -123
  43. package/dist/_ssrf.d.ts +0 -30
  44. package/dist/_ssrf.js +0 -2
  45. package/dist/_utils-DgzpOMSV.js +0 -61
  46. package/dist/direct-executor-B-5mq3cu.js +0 -570
  47. package/dist/kv-iXtikQmR.js +0 -32
  48. package/dist/middleware-core-BwyBIPed.js +0 -107
  49. package/dist/middleware-core.d.ts +0 -47
  50. package/dist/middleware-core.js +0 -2
  51. package/dist/middleware.d.ts +0 -37
  52. package/dist/protocol-B-H2Q4ox.js +0 -162
  53. package/dist/runtime-CxcwaK68.js +0 -58
  54. package/dist/runtime.js +0 -2
  55. package/dist/s2s-M7JqtgFw.js +0 -272
  56. package/dist/s2s.js +0 -2
  57. package/dist/session-BYlwcrya.js +0 -683
  58. package/dist/session.js +0 -2
  59. package/dist/telemetry-CJlaDFNc.js +0 -95
  60. package/dist/telemetry.d.ts +0 -49
  61. package/dist/telemetry.js +0 -2
  62. package/dist/types-D8ZBxTL_.js +0 -192
  63. package/dist/unstorage-kv-CDgP-frt.js +0 -64
  64. package/dist/unstorage-kv.js +0 -2
  65. package/dist/unstorage-vector-Cj5llNhg.js +0 -172
  66. package/dist/unstorage-vector.d.ts +0 -47
  67. package/dist/unstorage-vector.js +0 -2
  68. package/dist/vector.d.ts +0 -86
  69. package/dist/vector.js +0 -49
  70. package/dist/worker-entry-2jaiqIj0.js +0 -70
  71. package/dist/worker-entry.d.ts +0 -47
  72. package/dist/worker-entry.js +0 -2
  73. package/dist/ws-handler-C0Q6eSay.js +0 -207
  74. package/dist/ws-handler.js +0 -2
@@ -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.getTracer(SCOPE, VERSION);
27
- /** Meter scoped to the AAI SDK. */
28
- const meter = metrics.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.OK });
69
- span.end();
70
- return v;
71
- }).catch((err) => {
72
- span.setStatus({
73
- code: SpanStatusCode.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.OK });
81
- span.end();
82
- return result;
83
- } catch (err) {
84
- span.setStatus({
85
- code: SpanStatusCode.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 { turnStepsHistogram as _, idleTimeoutCounter as a, s2sConnectionDuration as c, toolCallCounter as d, toolCallDuration as f, turnCounter as g, tracer as h, context as i, s2sErrorCounter as l, trace$1 as m, activeSessionsUpDown as n, meter as o, toolCallErrorCounter as p, bargeInCounter as r, metrics$1 as s, SpanStatusCode$1 as t, sessionCounter as u, withSpan as v, wsSendDroppedCounter as y };
@@ -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,2 +0,0 @@
1
- import { _ as turnStepsHistogram, a as idleTimeoutCounter, c as s2sConnectionDuration, d as toolCallCounter, f as toolCallDuration, g as turnCounter, h as tracer, i as context, l as s2sErrorCounter, m as trace, n as activeSessionsUpDown, o as meter, p as toolCallErrorCounter, r as bargeInCounter, s as metrics, t as SpanStatusCode, u as sessionCounter, v as withSpan, y as wsSendDroppedCounter } from "./telemetry-CJlaDFNc.js";
2
- export { SpanStatusCode, activeSessionsUpDown, bargeInCounter, context, idleTimeoutCounter, meter, metrics, s2sConnectionDuration, s2sErrorCounter, sessionCounter, toolCallCounter, toolCallDuration, toolCallErrorCounter, trace, tracer, turnCounter, turnStepsHistogram, withSpan, wsSendDroppedCounter };
@@ -1,192 +0,0 @@
1
- import { z } from "zod";
2
- //#region types.ts
3
- /**
4
- * Core type definitions for the AAI agent SDK.
5
- */
6
- /**
7
- * Identity helper that preserves the Zod schema generic for type inference.
8
- *
9
- * When tools are defined inline in `defineAgent({ tools: { ... } })`, the
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
- * `defineTool()` lets TypeScript infer `P` from `parameters` and type
13
- * `args` correctly.
14
- *
15
- * @example
16
- * ```ts
17
- * import { defineAgent, defineTool } from "aai";
18
- * import { z } from "zod";
19
- *
20
- * export default defineAgent({
21
- * name: "my-agent",
22
- * tools: {
23
- * greet: defineTool({
24
- * description: "Greet the user",
25
- * parameters: z.object({ name: z.string() }),
26
- * execute: ({ name }) => `Hello, ${name}!`, // name is string
27
- * }),
28
- * },
29
- * });
30
- * ```
31
- *
32
- * @public
33
- */
34
- function defineTool(def) {
35
- return def;
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
- /**
75
- * Default system prompt used when `instructions` is not provided.
76
- *
77
- * Optimized for voice-first interactions: short sentences, no visual
78
- * formatting, confident tone, and concise answers.
79
- */
80
- const DEFAULT_INSTRUCTIONS = `\
81
- You are AAI, a helpful AI assistant.
82
-
83
- Voice-First Rules:
84
- - Optimize for natural speech. Avoid jargon unless central to the answer. \
85
- Use short, punchy sentences.
86
- - Never mention "search results," "sources," or "the provided text." \
87
- Speak as if the knowledge is your own.
88
- - No visual formatting. Do not say "bullet point," "bold," or "bracketed one." \
89
- If you need to list items, say "First," "Next," and "Finally."
90
- - Start with the most important information. No introductory filler.
91
- - Be concise. Keep answers to 1-3 sentences. For complex topics, provide a high-level summary.
92
- - Be confident. Avoid hedging phrases like "It seems that" or "I believe."
93
- - If you don't have enough information, say so directly rather than guessing.
94
- - Never use exclamation points. Keep your tone calm and conversational.`;
95
- /** Default greeting spoken when a session starts. */
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. */
98
- const BuiltinToolSchema = z.enum([
99
- "web_search",
100
- "visit_webpage",
101
- "fetch_json",
102
- "run_code",
103
- "vector_search",
104
- "memory"
105
- ]);
106
- /** @internal Zod schema for {@link ToolChoice}. Exported for reuse in internal schemas. */
107
- const ToolChoiceSchema = z.union([z.enum([
108
- "auto",
109
- "required",
110
- "none"
111
- ]), z.object({
112
- type: z.literal("tool"),
113
- toolName: z.string().min(1)
114
- })]);
115
- const ToolDefSchema = z.object({
116
- description: z.string().min(1, "Tool description must be non-empty"),
117
- parameters: z.custom((val) => val === void 0 || val instanceof z.ZodType, "Expected a Zod schema").optional(),
118
- execute: z.function()
119
- });
120
- /** Default TTL for persisted session data: 1 hour. */
121
- const DEFAULT_PERSIST_TTL = 36e5;
122
- const AgentOptionsSchema = z.object({
123
- name: z.string().min(1, "Agent name must be non-empty"),
124
- instructions: z.string().optional(),
125
- greeting: z.string().optional(),
126
- sttPrompt: z.string().optional(),
127
- maxSteps: z.union([z.number().int().positive(), z.function()]).optional(),
128
- toolChoice: ToolChoiceSchema.optional(),
129
- builtinTools: z.array(BuiltinToolSchema).optional(),
130
- tools: z.record(z.string(), ToolDefSchema).optional(),
131
- state: z.function().optional(),
132
- persistence: z.union([z.literal(true), z.object({ ttl: z.number().int().positive().optional() })]).optional(),
133
- onConnect: z.function().optional(),
134
- onDisconnect: z.function().optional(),
135
- onError: z.function().optional(),
136
- onTurn: z.function().optional(),
137
- onStep: z.function().optional(),
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()
148
- });
149
- /**
150
- * Create an agent definition from the given options, applying sensible defaults.
151
- *
152
- * This is the main entry point for defining a voice agent. The returned
153
- * `AgentDef` is consumed by the AAI server at deploy time.
154
- *
155
- * @param options - Configuration for the agent including name, instructions,
156
- * tools, hooks, and other settings.
157
- * @returns A fully resolved agent definition with all defaults applied.
158
- *
159
- * @public
160
- *
161
- * @example Basic agent with a custom tool
162
- * ```ts
163
- * import { defineAgent } from "aai";
164
- * import { z } from "zod";
165
- *
166
- * export default defineAgent({
167
- * name: "greeter",
168
- * instructions: "You greet people warmly.",
169
- * tools: {
170
- * greet: {
171
- * description: "Greet a user by name",
172
- * parameters: z.object({ name: z.string() }),
173
- * execute: ({ name }) => `Hello, ${name}!`,
174
- * },
175
- * },
176
- * });
177
- * ```
178
- */
179
- function defineAgent(options) {
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;
182
- return {
183
- ...options,
184
- instructions: options.instructions ?? DEFAULT_INSTRUCTIONS,
185
- greeting: options.greeting ?? "Hey there. I'm a voice assistant. What can I help you with?",
186
- maxSteps: options.maxSteps ?? 5,
187
- tools: options.tools ?? {},
188
- persistence
189
- };
190
- }
191
- //#endregion
192
- export { createToolFactory as a, ToolChoiceSchema as i, DEFAULT_GREETING as n, defineAgent as o, DEFAULT_INSTRUCTIONS as r, defineTool as s, BuiltinToolSchema as t };
@@ -1,64 +0,0 @@
1
- import { n as matchGlob, r as sortAndPaginate, t as MAX_VALUE_SIZE } from "./kv-iXtikQmR.js";
2
- import { prefixStorage } from "unstorage";
3
- //#region unstorage-kv.ts
4
- /**
5
- * Key-value store backed by unstorage.
6
- *
7
- * Works with any unstorage driver (memory, fs, S3/R2, etc.).
8
- */
9
- /**
10
- * Create a KV store backed by any unstorage driver.
11
- *
12
- * @param options - See {@link UnstorageKvOptions}.
13
- * @returns A {@link Kv} instance.
14
- *
15
- * @example
16
- * ```ts
17
- * import { createStorage } from "unstorage";
18
- * import { createUnstorageKv } from "@alexkroman1/aai/unstorage-kv";
19
- *
20
- * const kv = createUnstorageKv({ storage: createStorage() });
21
- * await kv.set("greeting", "hello");
22
- * const value = await kv.get<string>("greeting"); // "hello"
23
- * ```
24
- */
25
- function createUnstorageKv(options) {
26
- const store = options.prefix ? prefixStorage(options.storage, options.prefix) : options.storage;
27
- return {
28
- async get(key) {
29
- return await store.getItem(key) ?? null;
30
- },
31
- async set(key, value, setOptions) {
32
- if (JSON.stringify(value).length > 65536) throw new Error(`Value exceeds max size of ${MAX_VALUE_SIZE} bytes`);
33
- const storable = value;
34
- if (setOptions?.expireIn && setOptions.expireIn > 0) await store.setItem(key, storable, { ttl: Math.ceil(setOptions.expireIn / 1e3) });
35
- else await store.setItem(key, storable);
36
- },
37
- async delete(keys) {
38
- const keyArray = Array.isArray(keys) ? keys : [keys];
39
- await Promise.all(keyArray.map((k) => store.removeItem(k)));
40
- },
41
- async list(listPrefix, listOptions) {
42
- const allKeys = await store.getKeys(listPrefix);
43
- const entries = [];
44
- for (const key of allKeys) {
45
- const value = await store.getItem(key);
46
- if (value != null) entries.push({
47
- key,
48
- value
49
- });
50
- }
51
- return sortAndPaginate(entries, listOptions);
52
- },
53
- async keys(pattern) {
54
- const allKeys = await store.getKeys();
55
- if (!pattern) return allKeys.sort((a, b) => a.localeCompare(b));
56
- return allKeys.filter((key) => matchGlob(key, pattern)).sort((a, b) => a.localeCompare(b));
57
- },
58
- close() {
59
- store.dispose();
60
- }
61
- };
62
- }
63
- //#endregion
64
- export { createUnstorageKv as t };
@@ -1,2 +0,0 @@
1
- import { t as createUnstorageKv } from "./unstorage-kv-CDgP-frt.js";
2
- export { createUnstorageKv };
@@ -1,172 +0,0 @@
1
- const DEFAULT_MODEL = "Xenova/all-MiniLM-L6-v2";
2
- /**
3
- * Create a local embedding function using `all-MiniLM-L6-v2`.
4
- *
5
- * The model is downloaded on first use (~86 MB) and cached locally.
6
- * Subsequent calls load from cache in ~90ms. Each embedding takes <2ms.
7
- */
8
- function createLocalEmbedFn(cacheDir) {
9
- let pipelinePromise = null;
10
- async function getPipeline() {
11
- if (!pipelinePromise) pipelinePromise = (async () => {
12
- const { pipeline, env } = await import("@huggingface/transformers");
13
- env.cacheDir = cacheDir;
14
- return pipeline("feature-extraction", DEFAULT_MODEL);
15
- })();
16
- return pipelinePromise;
17
- }
18
- return async (text) => {
19
- const output = await (await getPipeline())(text, {
20
- pooling: "mean",
21
- normalize: true
22
- });
23
- return Array.from(output.data);
24
- };
25
- }
26
- /**
27
- * Create a deterministic hash-based embedding function for testing.
28
- *
29
- * Produces repeatable vectors where similar text yields similar embeddings.
30
- * Not suitable for production — use the default local model instead.
31
- *
32
- * @param dimensions - Vector dimensions (default: 384).
33
- */
34
- function createTestEmbedFn(dimensions = 384) {
35
- return async (text) => {
36
- const vec = new Float32Array(dimensions);
37
- const words = text.toLowerCase().split(/\s+/).filter(Boolean);
38
- for (const word of words) {
39
- let hash = 0;
40
- for (let i = 0; i < word.length; i++) hash = (hash << 5) - hash + word.charCodeAt(i) | 0;
41
- for (let i = 0; i < 8; i++) {
42
- const idx = Math.abs((hash + i * 31337) % dimensions);
43
- vec[idx] = (vec[idx] ?? 0) + 1;
44
- }
45
- }
46
- let norm = 0;
47
- for (let i = 0; i < dimensions; i++) norm += (vec[i] ?? 0) * (vec[i] ?? 0);
48
- norm = Math.sqrt(norm) || 1;
49
- return Array.from(vec, (v) => v / norm);
50
- };
51
- }
52
- /** Cosine similarity between two Float32Array vectors. */
53
- function cosineSimilarity(a, b) {
54
- let dot = 0;
55
- let normA = 0;
56
- let normB = 0;
57
- for (let i = 0; i < a.length; i++) {
58
- const ai = a[i] ?? 0;
59
- const bi = b[i] ?? 0;
60
- dot += ai * bi;
61
- normA += ai * ai;
62
- normB += bi * bi;
63
- }
64
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
65
- return denom === 0 ? 0 : dot / denom;
66
- }
67
- /** Encode an embedding as a base64 string. */
68
- function encodeEmbedding(vec) {
69
- const f32 = vec instanceof Float32Array ? vec : new Float32Array(vec);
70
- return Buffer.from(f32.buffer, f32.byteOffset, f32.byteLength).toString("base64");
71
- }
72
- /** Decode a base64 string back to a Float32Array embedding. */
73
- function decodeEmbedding(b64) {
74
- const buf = Buffer.from(b64, "base64");
75
- return new Float32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
76
- }
77
- //#endregion
78
- //#region unstorage-vector.ts
79
- /**
80
- * Create a vector store backed by any unstorage driver.
81
- *
82
- * All vectors for the scope are stored in a single blob. The blob is loaded
83
- * lazily on first operation and cached in memory. Mutations are written
84
- * through immediately.
85
- *
86
- * @param options - See {@link UnstorageVectorOptions}.
87
- * @returns A {@link VectorStore} instance.
88
- *
89
- * @example
90
- * ```ts
91
- * import { createStorage } from "unstorage";
92
- * import { createUnstorageVectorStore } from "@alexkroman1/aai/unstorage-vector";
93
- *
94
- * const vector = createUnstorageVectorStore({ storage: createStorage() });
95
- * await vector.upsert("doc-1", "The capital of France is Paris.");
96
- * const results = await vector.query("France capital");
97
- * ```
98
- */
99
- function createUnstorageVectorStore(options) {
100
- const { storage, blobKey = "vectors.json", dimensions = 384, modelCacheDir = ".aai/models" } = options;
101
- const embedFn = options.embedFn ?? createLocalEmbedFn(modelCacheDir);
102
- let cache = null;
103
- async function loadCache() {
104
- if (cache) return cache;
105
- cache = /* @__PURE__ */ new Map();
106
- const raw = await storage.getItem(blobKey);
107
- if (raw != null) {
108
- const blob = raw;
109
- for (const [id, entry] of Object.entries(blob.entries)) {
110
- const cached = {
111
- data: entry.data,
112
- embedding: decodeEmbedding(entry.emb)
113
- };
114
- if (entry.meta) cached.metadata = entry.meta;
115
- cache.set(id, cached);
116
- }
117
- }
118
- return cache;
119
- }
120
- async function flushCache() {
121
- if (!cache) return;
122
- const entries = {};
123
- for (const [id, entry] of cache) entries[id] = {
124
- data: entry.data,
125
- ...entry.metadata ? { meta: entry.metadata } : {},
126
- emb: encodeEmbedding(entry.embedding)
127
- };
128
- const blob = {
129
- v: 1,
130
- d: dimensions,
131
- entries
132
- };
133
- await storage.setItem(blobKey, blob);
134
- }
135
- return {
136
- async upsert(id, data, metadata) {
137
- const c = await loadCache();
138
- const vector = await embedFn(data);
139
- const entry = {
140
- data,
141
- embedding: new Float32Array(vector)
142
- };
143
- if (metadata) entry.metadata = metadata;
144
- c.set(id, entry);
145
- await flushCache();
146
- },
147
- async query(text, queryOptions) {
148
- const topK = queryOptions?.topK ?? 10;
149
- if (queryOptions?.filter) throw new Error("Metadata filter is not supported by the unstorage vector store");
150
- if (!text.trim()) return [];
151
- const c = await loadCache();
152
- const queryVec = new Float32Array(await embedFn(text));
153
- const scored = [];
154
- for (const [id, entry] of c) scored.push({
155
- id,
156
- score: cosineSimilarity(queryVec, entry.embedding),
157
- data: entry.data,
158
- metadata: entry.metadata
159
- });
160
- scored.sort((a, b) => b.score - a.score);
161
- return scored.slice(0, topK);
162
- },
163
- async delete(ids) {
164
- const c = await loadCache();
165
- const idArray = Array.isArray(ids) ? ids : [ids];
166
- for (const id of idArray) c.delete(id);
167
- await flushCache();
168
- }
169
- };
170
- }
171
- //#endregion
172
- export { createTestEmbedFn as n, createUnstorageVectorStore as t };
@@ -1,47 +0,0 @@
1
- /**
2
- * Vector store backed by unstorage.
3
- *
4
- * Stores all vectors for a scope in a single blob (JSON with base64-encoded
5
- * embeddings). Works with any unstorage driver. Brute-force cosine similarity
6
- * — fast for <10k vectors.
7
- */
8
- import type { Storage } from "unstorage";
9
- import { type EmbedFn } from "./_embeddings.ts";
10
- import type { VectorStore } from "./vector.ts";
11
- export { createTestEmbedFn, type EmbedFn } from "./_embeddings.ts";
12
- /**
13
- * Options for creating an unstorage-backed vector store.
14
- */
15
- export type UnstorageVectorOptions = {
16
- /** Configured unstorage Storage instance. */
17
- storage: Storage;
18
- /** Key for the vector blob in storage. Defaults to `"vectors.json"`. */
19
- blobKey?: 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 vector store backed by any unstorage driver.
29
- *
30
- * All vectors for the scope are stored in a single blob. The blob is loaded
31
- * lazily on first operation and cached in memory. Mutations are written
32
- * through immediately.
33
- *
34
- * @param options - See {@link UnstorageVectorOptions}.
35
- * @returns A {@link VectorStore} instance.
36
- *
37
- * @example
38
- * ```ts
39
- * import { createStorage } from "unstorage";
40
- * import { createUnstorageVectorStore } from "@alexkroman1/aai/unstorage-vector";
41
- *
42
- * const vector = createUnstorageVectorStore({ storage: createStorage() });
43
- * await vector.upsert("doc-1", "The capital of France is Paris.");
44
- * const results = await vector.query("France capital");
45
- * ```
46
- */
47
- export declare function createUnstorageVectorStore(options: UnstorageVectorOptions): VectorStore;
@@ -1,2 +0,0 @@
1
- import { n as createTestEmbedFn, t as createUnstorageVectorStore } from "./unstorage-vector-Cj5llNhg.js";
2
- export { createTestEmbedFn, createUnstorageVectorStore };