@mondaydotcomorg/atp-runtime 0.17.14

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 (137) hide show
  1. package/README.md +389 -0
  2. package/dist/approval/handler.d.ts +12 -0
  3. package/dist/approval/handler.d.ts.map +1 -0
  4. package/dist/approval/handler.js +17 -0
  5. package/dist/approval/handler.js.map +1 -0
  6. package/dist/approval/index.d.ts +17 -0
  7. package/dist/approval/index.d.ts.map +1 -0
  8. package/dist/approval/index.js +94 -0
  9. package/dist/approval/index.js.map +1 -0
  10. package/dist/approval/types.d.ts +21 -0
  11. package/dist/approval/types.d.ts.map +1 -0
  12. package/dist/approval/types.js +5 -0
  13. package/dist/approval/types.js.map +1 -0
  14. package/dist/cache/backends.d.ts +39 -0
  15. package/dist/cache/backends.d.ts.map +1 -0
  16. package/dist/cache/backends.js +167 -0
  17. package/dist/cache/backends.js.map +1 -0
  18. package/dist/cache/index.d.ts +32 -0
  19. package/dist/cache/index.d.ts.map +1 -0
  20. package/dist/cache/index.js +103 -0
  21. package/dist/cache/index.js.map +1 -0
  22. package/dist/cache/types.d.ts +20 -0
  23. package/dist/cache/types.d.ts.map +1 -0
  24. package/dist/cache/types.js +2 -0
  25. package/dist/cache/types.js.map +1 -0
  26. package/dist/embedding/index.d.ts +39 -0
  27. package/dist/embedding/index.d.ts.map +1 -0
  28. package/dist/embedding/index.js +162 -0
  29. package/dist/embedding/index.js.map +1 -0
  30. package/dist/embedding/types.d.ts +28 -0
  31. package/dist/embedding/types.d.ts.map +1 -0
  32. package/dist/embedding/types.js +5 -0
  33. package/dist/embedding/types.js.map +1 -0
  34. package/dist/embedding/utils.d.ts +11 -0
  35. package/dist/embedding/utils.d.ts.map +1 -0
  36. package/dist/embedding/utils.js +30 -0
  37. package/dist/embedding/utils.js.map +1 -0
  38. package/dist/embedding/vector-store.d.ts +64 -0
  39. package/dist/embedding/vector-store.d.ts.map +1 -0
  40. package/dist/embedding/vector-store.js +142 -0
  41. package/dist/embedding/vector-store.js.map +1 -0
  42. package/dist/index.d.ts +18 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +17 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/llm/callback.d.ts +13 -0
  47. package/dist/llm/callback.d.ts.map +1 -0
  48. package/dist/llm/callback.js +19 -0
  49. package/dist/llm/callback.js.map +1 -0
  50. package/dist/llm/index.d.ts +29 -0
  51. package/dist/llm/index.d.ts.map +1 -0
  52. package/dist/llm/index.js +118 -0
  53. package/dist/llm/index.js.map +1 -0
  54. package/dist/llm/replay.d.ts +47 -0
  55. package/dist/llm/replay.d.ts.map +1 -0
  56. package/dist/llm/replay.js +114 -0
  57. package/dist/llm/replay.js.map +1 -0
  58. package/dist/llm/types.d.ts +24 -0
  59. package/dist/llm/types.d.ts.map +1 -0
  60. package/dist/llm/types.js +2 -0
  61. package/dist/llm/types.js.map +1 -0
  62. package/dist/log/index.d.ts +12 -0
  63. package/dist/log/index.d.ts.map +1 -0
  64. package/dist/log/index.js +166 -0
  65. package/dist/log/index.js.map +1 -0
  66. package/dist/log/types.d.ts +19 -0
  67. package/dist/log/types.d.ts.map +1 -0
  68. package/dist/log/types.js +5 -0
  69. package/dist/log/types.js.map +1 -0
  70. package/dist/metadata/decorators.d.ts +27 -0
  71. package/dist/metadata/decorators.d.ts.map +1 -0
  72. package/dist/metadata/decorators.js +38 -0
  73. package/dist/metadata/decorators.js.map +1 -0
  74. package/dist/metadata/generated.d.ts +18 -0
  75. package/dist/metadata/generated.d.ts.map +1 -0
  76. package/dist/metadata/generated.js +290 -0
  77. package/dist/metadata/generated.js.map +1 -0
  78. package/dist/metadata/index.d.ts +11 -0
  79. package/dist/metadata/index.d.ts.map +1 -0
  80. package/dist/metadata/index.js +45 -0
  81. package/dist/metadata/index.js.map +1 -0
  82. package/dist/metadata/types.d.ts +22 -0
  83. package/dist/metadata/types.d.ts.map +1 -0
  84. package/dist/metadata/types.js +6 -0
  85. package/dist/metadata/types.js.map +1 -0
  86. package/dist/pause/index.d.ts +11 -0
  87. package/dist/pause/index.d.ts.map +1 -0
  88. package/dist/pause/index.js +15 -0
  89. package/dist/pause/index.js.map +1 -0
  90. package/dist/pause/types.d.ts +46 -0
  91. package/dist/pause/types.d.ts.map +1 -0
  92. package/dist/pause/types.js +57 -0
  93. package/dist/pause/types.js.map +1 -0
  94. package/dist/progress/index.d.ts +19 -0
  95. package/dist/progress/index.d.ts.map +1 -0
  96. package/dist/progress/index.js +61 -0
  97. package/dist/progress/index.js.map +1 -0
  98. package/dist/progress/types.d.ts +7 -0
  99. package/dist/progress/types.d.ts.map +1 -0
  100. package/dist/progress/types.js +2 -0
  101. package/dist/progress/types.js.map +1 -0
  102. package/dist/registry.d.ts +16 -0
  103. package/dist/registry.d.ts.map +1 -0
  104. package/dist/registry.js +16 -0
  105. package/dist/registry.js.map +1 -0
  106. package/dist/utils.d.ts +11 -0
  107. package/dist/utils.d.ts.map +1 -0
  108. package/dist/utils.js +31 -0
  109. package/dist/utils.js.map +1 -0
  110. package/package.json +51 -0
  111. package/src/approval/handler.ts +26 -0
  112. package/src/approval/index.ts +95 -0
  113. package/src/approval/types.ts +23 -0
  114. package/src/cache/backends.ts +196 -0
  115. package/src/cache/index.ts +74 -0
  116. package/src/cache/types.ts +20 -0
  117. package/src/embedding/index.ts +153 -0
  118. package/src/embedding/types.ts +31 -0
  119. package/src/embedding/utils.ts +34 -0
  120. package/src/embedding/vector-store.ts +164 -0
  121. package/src/index.ts +35 -0
  122. package/src/llm/callback.ts +24 -0
  123. package/src/llm/index.ts +121 -0
  124. package/src/llm/replay.ts +141 -0
  125. package/src/llm/types.ts +29 -0
  126. package/src/log/index.ts +167 -0
  127. package/src/log/types.ts +21 -0
  128. package/src/metadata/decorators.ts +44 -0
  129. package/src/metadata/generated.ts +293 -0
  130. package/src/metadata/index.ts +61 -0
  131. package/src/metadata/types.ts +24 -0
  132. package/src/pause/index.ts +28 -0
  133. package/src/pause/types.ts +57 -0
  134. package/src/progress/index.ts +50 -0
  135. package/src/progress/types.ts +6 -0
  136. package/src/registry.ts +22 -0
  137. package/src/utils.ts +37 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Human Approval API Types
3
+ */
4
+
5
+ export interface ApprovalRequest {
6
+ message: string;
7
+ context?: Record<string, unknown>;
8
+ timeout?: number;
9
+ schema?: ApprovalSchema;
10
+ }
11
+
12
+ export interface ApprovalSchema {
13
+ type: 'boolean' | 'text' | 'choice' | 'structured';
14
+ choices?: string[];
15
+ structuredSchema?: Record<string, unknown>;
16
+ required?: boolean;
17
+ }
18
+
19
+ export interface ApprovalResponse<T = unknown> {
20
+ approved: boolean;
21
+ response?: T;
22
+ timestamp: number;
23
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ */
3
+ import NodeCache from 'node-cache';
4
+ import type { CacheBackend, CacheConfig } from './types';
5
+
6
+ /**
7
+ * In-memory cache implementation using node-cache
8
+ */
9
+ export class MemoryCacheBackend implements CacheBackend {
10
+ private cache: NodeCache;
11
+
12
+ constructor(config?: { maxKeys?: number; defaultTTL?: number; checkPeriod?: number }) {
13
+ this.cache = new NodeCache({
14
+ stdTTL: config?.defaultTTL ?? 600,
15
+ checkperiod: config?.checkPeriod ?? 120,
16
+ maxKeys: config?.maxKeys ?? 1000,
17
+ useClones: false,
18
+ });
19
+ }
20
+
21
+ async get<T>(key: string): Promise<T | null> {
22
+ const value = this.cache.get<T>(key);
23
+ return value ?? null;
24
+ }
25
+
26
+ async set(key: string, value: unknown, ttl?: number): Promise<void> {
27
+ if (ttl) {
28
+ this.cache.set(key, value, ttl);
29
+ } else {
30
+ this.cache.set(key, value);
31
+ }
32
+ }
33
+
34
+ async delete(key: string): Promise<void> {
35
+ this.cache.del(key);
36
+ }
37
+
38
+ async has(key: string): Promise<boolean> {
39
+ return this.cache.has(key);
40
+ }
41
+
42
+ async clear(): Promise<void> {
43
+ this.cache.flushAll();
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Redis cache implementation (lazy-loaded only if configured)
49
+ */
50
+ export class RedisCacheBackend implements CacheBackend {
51
+ private client: any;
52
+ private connected: boolean = false;
53
+
54
+ constructor(config: NonNullable<CacheConfig['redis']>) {
55
+ import('ioredis')
56
+ .then((Redis) => {
57
+ this.client = new Redis.default({
58
+ host: config.host,
59
+ port: config.port,
60
+ password: config.password,
61
+ db: config.db ?? 0,
62
+ retryStrategy: (times: number) => {
63
+ if (times > 3) {
64
+ return null;
65
+ }
66
+ return Math.min(times * 100, 2000);
67
+ },
68
+ lazyConnect: true,
69
+ });
70
+
71
+ this.client
72
+ .connect()
73
+ .then(() => {
74
+ this.connected = true;
75
+ })
76
+ .catch(() => {
77
+ this.connected = false;
78
+ });
79
+ })
80
+ .catch(() => {
81
+ throw new Error('ioredis package not installed. Install it with: yarn add ioredis');
82
+ });
83
+ }
84
+
85
+ async get<T>(key: string): Promise<T | null> {
86
+ if (!this.connected) {
87
+ console.warn('[Redis Cache] Not connected, cannot get key:', key);
88
+ return null;
89
+ }
90
+ try {
91
+ const value = await this.client.get(key);
92
+ return value ? JSON.parse(value) : null;
93
+ } catch (error) {
94
+ console.error(
95
+ '[Redis Cache] Failed to get key:',
96
+ key,
97
+ error instanceof Error ? error.message : error
98
+ );
99
+ return null;
100
+ }
101
+ }
102
+
103
+ async set(key: string, value: unknown, ttl?: number): Promise<void> {
104
+ if (!this.connected) {
105
+ console.warn('[Redis Cache] Not connected, cannot set key:', key);
106
+ return;
107
+ }
108
+ try {
109
+ const serialized = JSON.stringify(value);
110
+ if (ttl) {
111
+ await this.client.setex(key, ttl, serialized);
112
+ } else {
113
+ await this.client.set(key, serialized);
114
+ }
115
+ } catch (error) {
116
+ console.error(
117
+ '[Redis Cache] Failed to set key:',
118
+ key,
119
+ error instanceof Error ? error.message : error
120
+ );
121
+ }
122
+ }
123
+
124
+ async delete(key: string): Promise<void> {
125
+ if (!this.connected) {
126
+ console.warn('[Redis Cache] Not connected, cannot delete key:', key);
127
+ return;
128
+ }
129
+ try {
130
+ await this.client.del(key);
131
+ } catch (error) {
132
+ console.error(
133
+ '[Redis Cache] Failed to delete key:',
134
+ key,
135
+ error instanceof Error ? error.message : error
136
+ );
137
+ }
138
+ }
139
+
140
+ async has(key: string): Promise<boolean> {
141
+ if (!this.connected) {
142
+ console.warn('[Redis Cache] Not connected, cannot check key:', key);
143
+ return false;
144
+ }
145
+ try {
146
+ const exists = await this.client.exists(key);
147
+ return exists === 1;
148
+ } catch (error) {
149
+ console.error(
150
+ '[Redis Cache] Failed to check key:',
151
+ key,
152
+ error instanceof Error ? error.message : error
153
+ );
154
+ return false;
155
+ }
156
+ }
157
+
158
+ async clear(): Promise<void> {
159
+ if (!this.connected) {
160
+ console.warn('[Redis Cache] Not connected, cannot clear cache');
161
+ return;
162
+ }
163
+ try {
164
+ await this.client.flushdb();
165
+ } catch (error) {
166
+ console.error(
167
+ '[Redis Cache] Failed to clear cache:',
168
+ error instanceof Error ? error.message : error
169
+ );
170
+ }
171
+ }
172
+ }
173
+
174
+ let cacheBackend: CacheBackend = new MemoryCacheBackend();
175
+
176
+ /**
177
+ * Initializes the cache system with configuration
178
+ */
179
+ export function initializeCache(config: CacheConfig): void {
180
+ if (config.type === 'redis' && config.redis) {
181
+ cacheBackend = new RedisCacheBackend(config.redis);
182
+ } else {
183
+ cacheBackend = new MemoryCacheBackend({
184
+ maxKeys: config.maxKeys,
185
+ defaultTTL: config.defaultTTL,
186
+ checkPeriod: config.checkPeriod,
187
+ });
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Get the current cache backend
193
+ */
194
+ export function getCacheBackend(): CacheBackend {
195
+ return cacheBackend;
196
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Cache API - Clean refactored version with decorators and extracted modules
3
+ *
4
+ * Benefits:
5
+ * - No duplication between implementation and metadata
6
+ * - Types auto-detected from TypeScript signatures
7
+ * - Clean separation of concerns (backends, API)
8
+ */
9
+ import { RuntimeAPI, RuntimeMethod } from '../metadata/decorators.js';
10
+ import { getCacheBackend } from './backends.js';
11
+
12
+ export type { CacheConfig, CacheBackend } from './types';
13
+ export { MemoryCacheBackend, RedisCacheBackend, initializeCache } from './backends.js';
14
+
15
+ /**
16
+ * Cache Runtime API
17
+ *
18
+ * Store and retrieve data with optional TTL (Time To Live).
19
+ * Supports in-memory (node-cache) and Redis backends.
20
+ */
21
+ @RuntimeAPI('cache', 'Cache API - Store and retrieve data with optional TTL')
22
+ class CacheAPI {
23
+ /**
24
+ * Gets a value from cache
25
+ */
26
+ @RuntimeMethod('Get a value from cache by key', {
27
+ key: { description: 'Cache key' },
28
+ })
29
+ async get<T>(key: string): Promise<T | null> {
30
+ return getCacheBackend().get<T>(key);
31
+ }
32
+
33
+ /**
34
+ * Sets a value in cache with optional TTL in seconds
35
+ */
36
+ @RuntimeMethod('Set a value in cache with optional TTL', {
37
+ key: { description: 'Cache key' },
38
+ value: { description: 'Value to cache', type: 'unknown' },
39
+ ttl: { description: 'Time to live in seconds', optional: true },
40
+ })
41
+ async set(key: string, value: unknown, ttl?: number): Promise<void> {
42
+ return getCacheBackend().set(key, value, ttl);
43
+ }
44
+
45
+ /**
46
+ * Deletes a value from cache
47
+ */
48
+ @RuntimeMethod('Delete a value from cache', {
49
+ key: { description: 'Cache key to delete' },
50
+ })
51
+ async delete(key: string): Promise<void> {
52
+ return getCacheBackend().delete(key);
53
+ }
54
+
55
+ /**
56
+ * Checks if a key exists in cache
57
+ */
58
+ @RuntimeMethod('Check if a key exists in cache', {
59
+ key: { description: 'Cache key to check' },
60
+ })
61
+ async has(key: string): Promise<boolean> {
62
+ return getCacheBackend().has(key);
63
+ }
64
+
65
+ /**
66
+ * Clears all cache entries
67
+ */
68
+ @RuntimeMethod('Clear all cache entries')
69
+ async clear(): Promise<void> {
70
+ return getCacheBackend().clear();
71
+ }
72
+ }
73
+
74
+ export const cache = new CacheAPI();
@@ -0,0 +1,20 @@
1
+ export interface CacheConfig {
2
+ type: 'memory' | 'redis';
3
+ redis?: {
4
+ host: string;
5
+ port: number;
6
+ password?: string;
7
+ db?: number;
8
+ };
9
+ maxKeys?: number;
10
+ defaultTTL?: number;
11
+ checkPeriod?: number;
12
+ }
13
+
14
+ export interface CacheBackend {
15
+ get<T>(key: string): Promise<T | null>;
16
+ set(key: string, value: unknown, ttl?: number): Promise<void>;
17
+ delete(key: string): Promise<void>;
18
+ has(key: string): Promise<boolean>;
19
+ clear(): Promise<void>;
20
+ }
@@ -0,0 +1,153 @@
1
+ import { pauseForCallback, CallbackType, EmbeddingOperation } from '../pause/index.js';
2
+ import { RuntimeAPI, RuntimeMethod } from '../metadata/decorators.js';
3
+ import { getVectorStore } from './vector-store.js';
4
+ import { cosineSimilarity, generateEmbeddingId } from './utils.js';
5
+ import { nextSequenceNumber, getCachedResult, shouldPauseForClient } from '../llm/replay.js';
6
+ import type { EmbeddingRecord, SearchOptions, SearchResult } from './types';
7
+
8
+ export type { EmbeddingOptions, EmbeddingRecord, SearchOptions, SearchResult } from './types';
9
+ export {
10
+ VectorStore,
11
+ initializeVectorStore,
12
+ clearVectorStore,
13
+ getVectorStore,
14
+ setVectorStoreExecutionId,
15
+ clearVectorStoreExecutionId,
16
+ } from './vector-store.js';
17
+ export { cosineSimilarity, generateEmbeddingId } from './utils.js';
18
+
19
+ /**
20
+ * Embedding Runtime API
21
+ *
22
+ * Decorators automatically:
23
+ * - Extract parameter names and types
24
+ * - Generate metadata for type definitions
25
+ * - Maintain single source of truth
26
+ */
27
+ @RuntimeAPI('embedding', 'Embedding API - Client-side embedding with server-side vector storage')
28
+ class EmbeddingAPI {
29
+ /**
30
+ * Request client to generate embedding and store it
31
+ * For batch inputs, returns array of IDs for stored embeddings
32
+ */
33
+ @RuntimeMethod('Request client to generate and store embeddings', {
34
+ input: {
35
+ description: 'Text(s) to embed',
36
+ type: 'string | string[]',
37
+ },
38
+ metadata: {
39
+ description: 'Optional metadata to store with embeddings',
40
+ optional: true,
41
+ type: 'Record<string, unknown>',
42
+ },
43
+ })
44
+ async embed(
45
+ input: string | string[],
46
+ metadata?: Record<string, unknown>
47
+ ): Promise<string | string[]> {
48
+ const isBatch = Array.isArray(input);
49
+ const texts = isBatch ? input : [input];
50
+ const ids = texts.map((_, i) => generateEmbeddingId(i));
51
+
52
+ const currentSequence = nextSequenceNumber();
53
+
54
+ const cachedResult = getCachedResult(currentSequence);
55
+ if (cachedResult !== undefined && cachedResult !== null) {
56
+ const vectorStore = getVectorStore();
57
+ const embedding = cachedResult as number[];
58
+ for (let i = 0; i < texts.length; i++) {
59
+ vectorStore.store(ids[i]!, texts[i]!, embedding, metadata);
60
+ }
61
+ return isBatch ? ids : ids[0]!;
62
+ }
63
+
64
+ if (shouldPauseForClient()) {
65
+ pauseForCallback(CallbackType.EMBEDDING, EmbeddingOperation.EMBED, {
66
+ text: isBatch ? texts.join('\n') : texts[0]!,
67
+ input,
68
+ ids,
69
+ metadata,
70
+ sequenceNumber: currentSequence,
71
+ });
72
+ }
73
+
74
+ throw new Error('Embedding service not provided by client');
75
+ }
76
+
77
+ /**
78
+ * Search stored embeddings by similarity
79
+ * Query must be embedded first via embed()
80
+ */
81
+ @RuntimeMethod('Search stored embeddings by similarity', {
82
+ query: {
83
+ description: 'Search query text (will be embedded by client)',
84
+ },
85
+ options: {
86
+ description: 'Search options (topK, minSimilarity, filter)',
87
+ optional: true,
88
+ type: 'SearchOptions',
89
+ },
90
+ })
91
+ async search(query: string, options?: Omit<SearchOptions, 'query'>): Promise<SearchResult[]> {
92
+ const currentSequence = nextSequenceNumber();
93
+ const vectorStore = getVectorStore();
94
+
95
+ const cachedQueryEmbedding = getCachedResult(currentSequence);
96
+ if (cachedQueryEmbedding !== undefined && cachedQueryEmbedding !== null) {
97
+ vectorStore.setQueryEmbedding(cachedQueryEmbedding as number[]);
98
+
99
+ const searchOptions: any = { ...options, query };
100
+ if ((options as any)?.collection) {
101
+ searchOptions.filter = {
102
+ ...searchOptions.filter,
103
+ collection: (options as any).collection,
104
+ };
105
+ }
106
+
107
+ return vectorStore.search(searchOptions);
108
+ }
109
+
110
+ if (shouldPauseForClient()) {
111
+ pauseForCallback(CallbackType.EMBEDDING, EmbeddingOperation.SEARCH, {
112
+ query,
113
+ options: {
114
+ ...options,
115
+ query,
116
+ },
117
+ sequenceNumber: currentSequence,
118
+ });
119
+ }
120
+
121
+ throw new Error('Embedding service not provided by client');
122
+ }
123
+
124
+ /**
125
+ * Calculate cosine similarity between two embedding vectors
126
+ * This is a utility function that doesn't require client interaction
127
+ */
128
+ @RuntimeMethod('Calculate cosine similarity between two embedding vectors', {
129
+ embedding1: { description: 'First embedding vector', type: 'number[]' },
130
+ embedding2: { description: 'Second embedding vector', type: 'number[]' },
131
+ })
132
+ similarity(embedding1: number[], embedding2: number[]): number {
133
+ return cosineSimilarity(embedding1, embedding2);
134
+ }
135
+
136
+ /**
137
+ * Get all stored embeddings (useful for debugging)
138
+ */
139
+ @RuntimeMethod('Get all stored embeddings')
140
+ getAll(): EmbeddingRecord[] {
141
+ return getVectorStore().getAll();
142
+ }
143
+
144
+ /**
145
+ * Get count of stored embeddings
146
+ */
147
+ @RuntimeMethod('Get count of stored embeddings')
148
+ count(): number {
149
+ return getVectorStore().count();
150
+ }
151
+ }
152
+
153
+ export const embedding = new EmbeddingAPI();
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Embedding API Types
3
+ */
4
+
5
+ export interface EmbeddingOptions {
6
+ input: string | string[];
7
+ model?: string;
8
+ dimensions?: number;
9
+ context?: Record<string, unknown>;
10
+ }
11
+
12
+ export interface EmbeddingRecord {
13
+ id: string;
14
+ text: string;
15
+ embedding: number[];
16
+ metadata?: Record<string, unknown>;
17
+ }
18
+
19
+ export interface SearchOptions {
20
+ query: string;
21
+ topK?: number;
22
+ minSimilarity?: number;
23
+ filter?: Record<string, unknown>;
24
+ }
25
+
26
+ export interface SearchResult {
27
+ id: string;
28
+ text: string;
29
+ similarity: number;
30
+ metadata?: Record<string, unknown>;
31
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+
3
+ /**
4
+ * Calculate cosine similarity between two vectors
5
+ */
6
+ export function cosineSimilarity(vec1: number[], vec2: number[]): number {
7
+ if (vec1.length !== vec2.length) {
8
+ throw new Error(`Vectors must have the same length (${vec1.length} vs ${vec2.length})`);
9
+ }
10
+
11
+ let dotProduct = 0;
12
+ let norm1 = 0;
13
+ let norm2 = 0;
14
+
15
+ for (let i = 0; i < vec1.length; i++) {
16
+ dotProduct += vec1[i]! * vec2[i]!;
17
+ norm1 += vec1[i]! * vec1[i]!;
18
+ norm2 += vec2[i]! * vec2[i]!;
19
+ }
20
+
21
+ const denominator = Math.sqrt(norm1) * Math.sqrt(norm2);
22
+ if (denominator === 0) {
23
+ return 0;
24
+ }
25
+
26
+ return dotProduct / denominator;
27
+ }
28
+
29
+ /**
30
+ * Generate a unique ID for an embedding
31
+ */
32
+ export function generateEmbeddingId(index: number = 0): string {
33
+ return `emb_${Date.now()}_${index}_${Math.random().toString(36).slice(2)}`;
34
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ */
3
+ import type { EmbeddingRecord, SearchOptions, SearchResult } from './types.js';
4
+ import { cosineSimilarity } from './utils.js';
5
+
6
+ /**
7
+ * In-memory vector store for the current execution
8
+ * Cleared after each execution completes
9
+ */
10
+ export class VectorStore {
11
+ private records: Map<string, EmbeddingRecord> = new Map();
12
+ private queryEmbedding: number[] | null = null;
13
+
14
+ /**
15
+ * Store embeddings from client response
16
+ */
17
+ store(id: string, text: string, embedding: number[], metadata?: Record<string, unknown>): void {
18
+ this.records.set(id, { id, text, embedding, metadata });
19
+ }
20
+
21
+ /**
22
+ * Store multiple embeddings
23
+ */
24
+ storeBatch(records: EmbeddingRecord[]): void {
25
+ for (const record of records) {
26
+ this.records.set(record.id, record);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Set the query embedding for search
32
+ */
33
+ setQueryEmbedding(embedding: number[]): void {
34
+ this.queryEmbedding = embedding;
35
+ }
36
+
37
+ /**
38
+ * Search stored embeddings by similarity to query
39
+ */
40
+ search(options: SearchOptions): SearchResult[] {
41
+ if (!this.queryEmbedding) {
42
+ throw new Error('No query embedding set. Call embed() with query first.');
43
+ }
44
+
45
+ const topK = options.topK ?? 5;
46
+ const minSimilarity = options.minSimilarity ?? 0;
47
+
48
+ const results: SearchResult[] = [];
49
+ for (const record of this.records.values()) {
50
+ if (options.filter && record.metadata) {
51
+ let matches = true;
52
+ for (const [key, value] of Object.entries(options.filter)) {
53
+ if (record.metadata[key] !== value) {
54
+ matches = false;
55
+ break;
56
+ }
57
+ }
58
+ if (!matches) continue;
59
+ }
60
+
61
+ const similarity = cosineSimilarity(this.queryEmbedding, record.embedding);
62
+ if (similarity >= minSimilarity) {
63
+ results.push({
64
+ id: record.id,
65
+ text: record.text,
66
+ similarity,
67
+ metadata: record.metadata,
68
+ });
69
+ }
70
+ }
71
+
72
+ results.sort((a, b) => b.similarity - a.similarity);
73
+ return results.slice(0, topK);
74
+ }
75
+
76
+ /**
77
+ * Get all stored embeddings
78
+ */
79
+ getAll(): EmbeddingRecord[] {
80
+ return Array.from(this.records.values());
81
+ }
82
+
83
+ /**
84
+ * Get embedding by ID
85
+ */
86
+ get(id: string): EmbeddingRecord | undefined {
87
+ return this.records.get(id);
88
+ }
89
+
90
+ /**
91
+ * Clear all stored embeddings
92
+ */
93
+ clear(): void {
94
+ this.records.clear();
95
+ this.queryEmbedding = null;
96
+ }
97
+
98
+ /**
99
+ * Get count of stored embeddings
100
+ */
101
+ count(): number {
102
+ return this.records.size;
103
+ }
104
+ }
105
+
106
+ const vectorStores = new Map<string, VectorStore>();
107
+
108
+ let currentVectorStoreExecutionId: string | null = null;
109
+
110
+ /**
111
+ * Set the current execution ID for vector store operations
112
+ */
113
+ export function setVectorStoreExecutionId(executionId: string): void {
114
+ currentVectorStoreExecutionId = executionId;
115
+ }
116
+
117
+ /**
118
+ * Clear the current execution ID
119
+ */
120
+ export function clearVectorStoreExecutionId(): void {
121
+ currentVectorStoreExecutionId = null;
122
+ }
123
+
124
+ /**
125
+ * Initialize a new vector store for a new execution
126
+ */
127
+ export function initializeVectorStore(executionId?: string): void {
128
+ const id = executionId || currentVectorStoreExecutionId;
129
+ if (!id) {
130
+ throw new Error('No execution ID set for vector store');
131
+ }
132
+ vectorStores.set(id, new VectorStore());
133
+ }
134
+
135
+ /**
136
+ * Clear the vector store after execution completes
137
+ */
138
+ export function clearVectorStore(executionId?: string): void {
139
+ const id = executionId || currentVectorStoreExecutionId;
140
+ if (!id) return;
141
+
142
+ const store = vectorStores.get(id);
143
+ if (store) {
144
+ store.clear();
145
+ vectorStores.delete(id);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Get the current vector store (for executor to manage)
151
+ */
152
+ export function getVectorStore(executionId?: string): VectorStore {
153
+ const id = executionId || currentVectorStoreExecutionId;
154
+ if (!id) {
155
+ throw new Error('No execution ID set for vector store');
156
+ }
157
+
158
+ let store = vectorStores.get(id);
159
+ if (!store) {
160
+ store = new VectorStore();
161
+ vectorStores.set(id, store);
162
+ }
163
+ return store;
164
+ }