@axiom-lattice/gateway 3.0.2 → 3.0.3

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 (155) hide show
  1. package/dist/index.js +31 -9
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +31 -9
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +9 -6
  6. package/.eslintrc.json +0 -22
  7. package/.turbo/turbo-build.log +0 -46
  8. package/AGENTS.md +0 -112
  9. package/CHANGELOG.md +0 -1190
  10. package/LOGGER_CONFIG.md +0 -135
  11. package/RESUME_STREAM_CONTENT_BASED.md +0 -326
  12. package/RESUME_STREAM_README.md +0 -388
  13. package/jest.config.js +0 -72
  14. package/public/sdk/README.md +0 -695
  15. package/public/sdk/dashboard-engine-skill.md +0 -1122
  16. package/public/sdk/dashboard-single-file-spec.md +0 -357
  17. package/public/sdk/data-query-sdk-skill.md +0 -307
  18. package/public/sdk/data-query-sdk.d.ts +0 -252
  19. package/public/sdk/data-query-sdk.js +0 -970
  20. package/public/sdk/occupancy-dashboard.html +0 -363
  21. package/public/sdk/test-dashboard.html +0 -690
  22. package/scripts/seed-lark-installation.ts +0 -54
  23. package/src/__tests__/__mocks__/e2b.ts +0 -1
  24. package/src/__tests__/a2a.test.ts +0 -428
  25. package/src/__tests__/channel-installations.test.ts +0 -199
  26. package/src/__tests__/data-query.test.ts +0 -77
  27. package/src/__tests__/sandbox-provider-registration.test.ts +0 -74
  28. package/src/__tests__/setup.ts +0 -5
  29. package/src/__tests__/workspace.test.ts +0 -400
  30. package/src/channels/__tests__/routes.test.ts +0 -50
  31. package/src/channels/lark/LarkChannelAdapter.ts +0 -217
  32. package/src/channels/lark/README.md +0 -187
  33. package/src/channels/lark/__tests__/controller.test.ts +0 -136
  34. package/src/channels/lark/__tests__/mapping-service.test.ts +0 -118
  35. package/src/channels/lark/__tests__/parser.test.ts +0 -72
  36. package/src/channels/lark/__tests__/sender.test.ts +0 -37
  37. package/src/channels/lark/__tests__/verification.test.ts +0 -157
  38. package/src/channels/lark/controller.ts +0 -48
  39. package/src/channels/lark/mapping-service.ts +0 -138
  40. package/src/channels/lark/parser.ts +0 -68
  41. package/src/channels/lark/routes.ts +0 -22
  42. package/src/channels/lark/sender.ts +0 -58
  43. package/src/channels/lark/types.ts +0 -20
  44. package/src/channels/lark/verification.ts +0 -32
  45. package/src/channels/registry.ts +0 -20
  46. package/src/channels/routes.ts +0 -30
  47. package/src/channels/wechat/WechatChannelAdapter.ts +0 -294
  48. package/src/channels/wechat/__tests__/context-store.test.ts +0 -148
  49. package/src/channels/wechat/context-store.ts +0 -54
  50. package/src/channels/wechat/controller.ts +0 -59
  51. package/src/channels/wechat/routes.ts +0 -7
  52. package/src/channels/wechat/types.ts +0 -62
  53. package/src/channels/wechat/wechat-client.ts +0 -162
  54. package/src/config/local-a2a-templates.ts +0 -59
  55. package/src/config.ts +0 -124
  56. package/src/controllers/__tests__/assistant-local-a2a.test.ts +0 -147
  57. package/src/controllers/__tests__/local-a2a-templates.test.ts +0 -112
  58. package/src/controllers/__tests__/mime.test.ts +0 -74
  59. package/src/controllers/__tests__/resources.test.ts +0 -122
  60. package/src/controllers/__tests__/run.test.ts +0 -115
  61. package/src/controllers/__tests__/tasks.test.ts +0 -215
  62. package/src/controllers/__tests__/workflow-tracking.test.ts +0 -113
  63. package/src/controllers/agent_task.ts +0 -72
  64. package/src/controllers/assistant.ts +0 -490
  65. package/src/controllers/auth.ts +0 -524
  66. package/src/controllers/channel-bindings.ts +0 -135
  67. package/src/controllers/channel-installations.ts +0 -409
  68. package/src/controllers/collections.ts +0 -176
  69. package/src/controllers/config.ts +0 -126
  70. package/src/controllers/connections.ts +0 -181
  71. package/src/controllers/data-query.ts +0 -236
  72. package/src/controllers/database-configs.ts +0 -440
  73. package/src/controllers/embeddings.ts +0 -22
  74. package/src/controllers/entries.ts +0 -167
  75. package/src/controllers/eval.ts +0 -513
  76. package/src/controllers/export-import.ts +0 -166
  77. package/src/controllers/health.ts +0 -36
  78. package/src/controllers/local-a2a-templates.ts +0 -18
  79. package/src/controllers/local-a2a.ts +0 -149
  80. package/src/controllers/mcp-configs.ts +0 -673
  81. package/src/controllers/memory.ts +0 -257
  82. package/src/controllers/menu-items.ts +0 -114
  83. package/src/controllers/metrics-configs.ts +0 -1061
  84. package/src/controllers/middleware-types.ts +0 -15
  85. package/src/controllers/models.ts +0 -199
  86. package/src/controllers/personal-assistant.ts +0 -191
  87. package/src/controllers/resources.ts +0 -477
  88. package/src/controllers/run.ts +0 -338
  89. package/src/controllers/sandbox.ts +0 -255
  90. package/src/controllers/schedules.ts +0 -336
  91. package/src/controllers/skills.ts +0 -256
  92. package/src/controllers/tasks.ts +0 -213
  93. package/src/controllers/tenants.ts +0 -121
  94. package/src/controllers/thread_status.ts +0 -66
  95. package/src/controllers/threads.ts +0 -260
  96. package/src/controllers/tools.ts +0 -139
  97. package/src/controllers/users.ts +0 -135
  98. package/src/controllers/workflow-tracking.ts +0 -693
  99. package/src/controllers/workspace.ts +0 -879
  100. package/src/export_registrations/a2a-api-key.registration.ts +0 -89
  101. package/src/export_registrations/agent.registration.ts +0 -80
  102. package/src/export_registrations/binding.registration.ts +0 -106
  103. package/src/export_registrations/channel-installation.registration.ts +0 -88
  104. package/src/export_registrations/collection.registration.ts +0 -85
  105. package/src/export_registrations/connection.registration.ts +0 -97
  106. package/src/export_registrations/database-config.registration.ts +0 -94
  107. package/src/export_registrations/eval.registration.ts +0 -334
  108. package/src/export_registrations/index.ts +0 -31
  109. package/src/export_registrations/mcp-config.registration.ts +0 -97
  110. package/src/export_registrations/menu.registration.ts +0 -91
  111. package/src/export_registrations/metrics-config.registration.ts +0 -94
  112. package/src/export_registrations/skill.registration.ts +0 -88
  113. package/src/export_registrations/task.registration.ts +0 -99
  114. package/src/index.ts +0 -497
  115. package/src/logger/Logger.ts +0 -186
  116. package/src/router/MessageContext.ts +0 -14
  117. package/src/router/MessageRouter.ts +0 -490
  118. package/src/router/middlewares/auditLogger.ts +0 -34
  119. package/src/router/middlewares/deduplication.ts +0 -38
  120. package/src/router/middlewares/index.ts +0 -3
  121. package/src/router/middlewares/rateLimit.ts +0 -46
  122. package/src/routes/__tests__/a2a-test-connection.test.ts +0 -177
  123. package/src/routes/a2a-bridge.ts +0 -266
  124. package/src/routes/a2a-test-connection.ts +0 -126
  125. package/src/routes/a2a.ts +0 -851
  126. package/src/routes/channel-bindings.ts +0 -11
  127. package/src/routes/channel-installations.ts +0 -33
  128. package/src/routes/index.ts +0 -640
  129. package/src/routes/menu-items.ts +0 -10
  130. package/src/routes/resource-routes.ts +0 -35
  131. package/src/routes/stt.ts +0 -102
  132. package/src/schemas/data-query.ts +0 -69
  133. package/src/schemas/index.ts +0 -852
  134. package/src/services/ExportImportService.ts +0 -296
  135. package/src/services/__tests__/ExportImportService.test.ts +0 -130
  136. package/src/services/__tests__/eval-runner.test.ts +0 -131
  137. package/src/services/__tests__/local-a2a.test.ts +0 -124
  138. package/src/services/agent_task_consumer.ts +0 -348
  139. package/src/services/collection_service.ts +0 -258
  140. package/src/services/eval-runner.ts +0 -283
  141. package/src/services/local-a2a.ts +0 -354
  142. package/src/services/queue_service.ts +0 -104
  143. package/src/services/sandbox_service.ts +0 -223
  144. package/src/services/skill_service.ts +0 -97
  145. package/src/services/supabase.ts +0 -60
  146. package/src/swagger.ts +0 -77
  147. package/src/types/index.ts +0 -118
  148. package/src/types/koa.d.ts +0 -7
  149. package/src/utils/__tests__/local-a2a-runtime.test.ts +0 -77
  150. package/src/utils/__tests__/path-containment.test.ts +0 -35
  151. package/src/utils/a2a-url.ts +0 -20
  152. package/src/utils/local-a2a-runtime.ts +0 -107
  153. package/src/utils/mime.ts +0 -44
  154. package/src/utils/path-containment.ts +0 -38
  155. package/tsconfig.json +0 -26
@@ -1,348 +0,0 @@
1
- import { eventBus, AGENT_TASK_EVENT, agentInstanceManager, QueueMode } from "@axiom-lattice/core";
2
- import { popAgentTaskFromQueue } from "./queue_service";
3
-
4
- // 任务请求结构
5
- export interface AgentTaskRequest {
6
- assistant_id: string;
7
- input: any;
8
- thread_id: string;
9
- "x-tenant-id": string;
10
- command?: any;
11
- callback_event?: string;
12
- runConfig?: Record<string, any>;
13
- main_thread_id?: string;
14
- main_tenant_id?: string;
15
- main_assistant_id?: string;
16
- }
17
-
18
- /**
19
- * 处理Agent任务事件
20
- * @param taskRequest 任务请求
21
- * @param retryCount 重试次数
22
- */
23
- const handleAgentTask = async (
24
- taskRequest: AgentTaskRequest,
25
- retryCount: number = 0
26
- ): Promise<boolean> => {
27
- const {
28
- assistant_id,
29
- input = {},
30
- thread_id,
31
- "x-tenant-id": tenant_id,
32
- command,
33
- callback_event,
34
- runConfig,
35
- main_thread_id,
36
- main_tenant_id,
37
- main_assistant_id,
38
- } = taskRequest;
39
-
40
-
41
- try {
42
- console.log(
43
- `开始处理任务 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
44
- );
45
-
46
- // 检查API服务器是否可用
47
- // const apiUrl = AgentTaskConsumer.agent_run_endpoint;
48
-
49
- // console.log(`apiUrl: ${apiUrl}`);
50
- const agent = agentInstanceManager.getAgent({ assistant_id, thread_id, tenant_id, workspace_id: runConfig?.workspaceId, project_id: runConfig?.projectId, custom_run_config: runConfig })
51
- await agent.addMessage({ input, command, custom_run_config: runConfig }, QueueMode.STEER);
52
- if (callback_event) {
53
- agent.subscribeOnce("message:completed", (evt) => {
54
- eventBus.publish(callback_event, {
55
- success: true,
56
- state: evt.state,
57
- });
58
-
59
- if (main_thread_id && main_tenant_id) {
60
- try {
61
- const mainAgent = agentInstanceManager.getAgent({
62
- assistant_id: main_assistant_id ?? assistant_id,
63
- thread_id: main_thread_id,
64
- tenant_id: main_tenant_id,
65
- workspace_id: runConfig?.workspaceId,
66
- project_id: runConfig?.projectId,
67
- });
68
- if (mainAgent) {
69
- const messages = evt.state?.values?.messages;
70
- const lastAIMessage = messages
71
- ?.filter((m: any) => m.type === 'ai' || m.getType?.() === 'ai')
72
- .pop();
73
- const summary = lastAIMessage?.content
74
- ?.substring(0, 500) ?? '(no output)';
75
-
76
- mainAgent.addMessage(
77
- {
78
- input: {
79
- message: `[Async task completed]\ntask_id: ${thread_id}\n${summary}`,
80
- },
81
- },
82
- ).catch((err: Error) => {
83
- console.error('Failed to notify main thread:', err);
84
- });
85
-
86
- mainAgent.updateAsyncTaskStatus(thread_id, 'completed');
87
- }
88
- } catch (err) {
89
- console.error('Failed to notify main thread:', err);
90
- }
91
- }
92
- })
93
- agent.subscribeOnce("message:interrupted", (evt) => {
94
- eventBus.publish(callback_event, {
95
- success: true,
96
- state: evt.state,
97
- });
98
- })
99
- }
100
-
101
- return true;
102
-
103
-
104
-
105
- } catch (error) {
106
- console.error(
107
- `Agent任务执行失败: ${assistant_id}, 线程: ${thread_id}`,
108
- error
109
- );
110
-
111
- // 重试逻辑,暂不用重试
112
- const maxRetries = 0;
113
- if (retryCount < maxRetries) {
114
- const nextRetryCount = retryCount + 1;
115
- const delayMs = Math.pow(2, nextRetryCount) * 1000; // 指数退避策略
116
-
117
- console.log(
118
- `将在 ${delayMs}ms 后重试任务 (${nextRetryCount}/${maxRetries})`
119
- );
120
-
121
- // 延迟后重试
122
- await new Promise((resolve) => setTimeout(resolve, delayMs));
123
- return handleAgentTask(taskRequest, nextRetryCount);
124
- }
125
-
126
- if (callback_event) {
127
- eventBus.publish(callback_event, {
128
- success: false,
129
- error: error instanceof Error ? error.message : String(error),
130
- });
131
- }
132
-
133
- console.error(
134
- `任务处理失败,已达到最大重试次数 [assistant_id: ${assistant_id}, thread_id: ${thread_id}]`
135
- );
136
- return false;
137
- }
138
- };
139
-
140
- /**
141
- * Agent任务消费者
142
- * 负责监听和执行Agent任务事件,同时从队列中消费任务
143
- */
144
- export class AgentTaskConsumer {
145
- private isPolling: boolean = false;
146
- private pollingInterval: NodeJS.Timeout | null = null;
147
- private pollingIntervalMs: number = 5000; // 默认5秒轮询一次
148
- private maxConcurrentTasks: number = 15; // 最大并发任务数
149
- private activeTasks: number = 0; // 当前活跃的任务数
150
- private processing: boolean = false; // 是否正在处理任务批次
151
- private immediateProcessingEnabled: boolean = true; // 是否启用即时处理模式
152
- public gatewayPort: number = 4001;
153
- public static agent_run_endpoint: string = "http://localhost:4001/api/runs";
154
-
155
- constructor(gatewayPort: number, pollingIntervalMs?: number) {
156
- this.gatewayPort = gatewayPort;
157
- AgentTaskConsumer.agent_run_endpoint = `http://localhost:${this.gatewayPort}/api/runs`;
158
- if (pollingIntervalMs) {
159
- this.pollingIntervalMs = pollingIntervalMs;
160
- }
161
- this.initialize();
162
- }
163
-
164
- /**
165
- * 初始化事件监听和队列轮询
166
- */
167
- private initialize(): void {
168
- // 监听事件总线上的任务
169
- eventBus.subscribe(AGENT_TASK_EVENT, this.trigger_agent_task.bind(this));
170
-
171
- // 启动队列轮询
172
- this.startPollingQueue();
173
-
174
- console.log("Agent任务消费者已启动并监听任务事件和队列");
175
- }
176
-
177
- /**
178
- * 启动队列轮询
179
- */
180
- startPollingQueue(): void {
181
- if (this.isPolling) {
182
- return;
183
- }
184
-
185
- this.isPolling = true;
186
-
187
- this.pollingInterval = setInterval(async () => {
188
- try {
189
- // 如果上一批次任务还在处理中,跳过本次轮询
190
- if (this.processing) {
191
- console.log("队列处理中,跳过本次轮询");
192
- return;
193
- }
194
-
195
- await this.consumeFromQueue();
196
- } catch (error) {
197
- console.error("队列轮询出错:", error);
198
- }
199
- }, this.pollingIntervalMs);
200
-
201
- console.log(
202
- `开始轮询队列,间隔: ${this.pollingIntervalMs}ms,最大并发任务数: ${this.maxConcurrentTasks}`
203
- );
204
- }
205
-
206
- /**
207
- * 停止队列轮询
208
- */
209
- stopPollingQueue(): void {
210
- if (this.pollingInterval) {
211
- clearInterval(this.pollingInterval);
212
- this.pollingInterval = null;
213
- this.isPolling = false;
214
- console.log("已停止队列轮询");
215
- }
216
- }
217
-
218
- /**
219
- * 处理单个任务并在完成后立即尝试处理下一个
220
- */
221
- async processNextTask(): Promise<boolean> {
222
- try {
223
- // 从队列中获取任务
224
- const queueResult = await popAgentTaskFromQueue();
225
-
226
- // 检查队列结果
227
- if (queueResult && queueResult.data) {
228
- const taskItem = queueResult.data;
229
-
230
- if (taskItem && typeof taskItem === "object") {
231
- const taskRequest = taskItem as AgentTaskRequest;
232
-
233
- console.log(
234
- `从队列中获取到任务 [assistant: ${taskRequest.assistant_id}, thread: ${taskRequest.thread_id}]`
235
- );
236
-
237
- // 增加活跃任务计数
238
- this.activeTasks++;
239
-
240
- // 处理任务(不使用await,允许并发执行)
241
- handleAgentTask(taskRequest)
242
- .then((success) => {
243
- if (!success) {
244
- console.error(`任务 处理失败`);
245
- // 可以在这里记录失败任务或执行补偿逻辑
246
- } else {
247
- console.log(`任务 处理成功`);
248
- }
249
- })
250
- .catch((error) => {
251
- console.error(`任务 处理时出错:`, error);
252
- })
253
- .finally(() => {
254
- // 减少活跃任务计数
255
- this.activeTasks--;
256
-
257
- // 如果启用了即时处理模式,尝试处理更多任务
258
- if (this.immediateProcessingEnabled && !this.processing) {
259
- this.checkQueueForTasks();
260
- }
261
- });
262
-
263
- // 任务已派发,返回true表示有任务被处理
264
- return true;
265
- } else {
266
- console.log("队列任务格式无效:", taskItem);
267
- return false;
268
- }
269
- } else {
270
- // 队列为空
271
- return false;
272
- }
273
- } catch (error) {
274
- console.error("处理任务失败:", error);
275
- return false;
276
- }
277
- }
278
-
279
- /**
280
- * 检查队列中是否有任务并处理
281
- */
282
- async checkQueueForTasks(): Promise<void> {
283
- // 如果已经在处理中或者并发任务已达上限,则不处理
284
- if (this.processing || this.activeTasks >= this.maxConcurrentTasks) {
285
- return;
286
- }
287
-
288
- this.processing = true;
289
-
290
- try {
291
- // 尝试获取并处理任务,直到达到并发上限
292
- while (this.activeTasks < this.maxConcurrentTasks) {
293
- const taskProcessed = await this.processNextTask();
294
- if (!taskProcessed) {
295
- // 没有更多任务,退出循环
296
- break;
297
- }
298
- }
299
- } catch (error) {
300
- console.error("检查队列任务失败:", error);
301
- } finally {
302
- this.processing = false;
303
- }
304
- }
305
-
306
- /**
307
- * 从队列中消费任务
308
- */
309
- async consumeFromQueue(): Promise<void> {
310
- // 如果已经在处理中,跳过
311
- if (this.processing) {
312
- return;
313
- }
314
-
315
- // 调用任务检查方法
316
- await this.checkQueueForTasks();
317
- }
318
-
319
- /**
320
- * 处理通过事件触发的任务
321
- */
322
- trigger_agent_task(taskRequest: AgentTaskRequest): void {
323
- console.log(
324
- `通过事件触发任务: [assistant: ${taskRequest.assistant_id}, thread: ${taskRequest.thread_id}]`
325
- );
326
-
327
- // 处理任务,不阻塞事件处理流程
328
- handleAgentTask(taskRequest).catch((error) => {
329
- console.error("处理Agent任务时发生未捕获的错误:", error);
330
-
331
- // 如果有回调事件,确保即使发生错误也能通知
332
- if (taskRequest.callback_event) {
333
- eventBus.publish(taskRequest.callback_event, {
334
- success: false,
335
- error: error instanceof Error ? error.message : String(error),
336
- });
337
- }
338
- });
339
-
340
- // 如果启用了即时处理且当前活跃任务数低于阈值,检查队列
341
- if (
342
- this.immediateProcessingEnabled &&
343
- this.activeTasks < this.maxConcurrentTasks
344
- ) {
345
- setImmediate(() => this.checkQueueForTasks());
346
- }
347
- }
348
- }
@@ -1,258 +0,0 @@
1
- /**
2
- * CollectionService
3
- *
4
- * Business logic layer for collection management and entry operations.
5
- * Uses CollectionLatticeManager for registration, VectorStoreLatticeManager for storage,
6
- * and EmbeddingsLatticeManager for vector embedding.
7
- * All vector store operations are tenant-isolated.
8
- */
9
-
10
- import { v4 as uuidv4 } from "uuid";
11
- import { Document } from "@langchain/core/documents";
12
- import {
13
- collectionLatticeManager,
14
- embeddingsLatticeManager,
15
- getOrCreateCollectionVectorStore,
16
- getCollectionEntryCount,
17
- listCollectionEntries,
18
- removeCollectionVectorStore,
19
- } from "@axiom-lattice/core";
20
- import type {
21
- Collection,
22
- CreateCollectionRequest,
23
- UpdateCollectionRequest,
24
- } from "@axiom-lattice/protocols";
25
- import { FastifyRequest } from "fastify";
26
-
27
- function getTenantId(request: FastifyRequest): string {
28
- return (
29
- (request as any).user?.tenantId ||
30
- (request.headers["x-tenant-id"] as string) ||
31
- "default"
32
- );
33
- }
34
-
35
- export interface EntryResponse {
36
- id: string;
37
- content: string;
38
- metadata: Record<string, unknown>;
39
- score?: number;
40
- }
41
-
42
- export class CollectionService {
43
- // ─── Collection CRUD ──────────────────────────────────────────
44
-
45
- async getAllCollections(request: FastifyRequest): Promise<Collection[]> {
46
- const tenantId = getTenantId(request);
47
- const collections = await collectionLatticeManager.getAllCollections(tenantId);
48
-
49
- for (const c of collections) {
50
- try {
51
- (c as any)._entryCount = await getCollectionEntryCount(c.name, c.embeddingKey, c.tenantId);
52
- } catch {
53
- (c as any)._entryCount = 0;
54
- }
55
- }
56
-
57
- return collections;
58
- }
59
-
60
- async getCollectionByName(
61
- request: FastifyRequest,
62
- name: string
63
- ): Promise<Collection | null> {
64
- const tenantId = getTenantId(request);
65
- return collectionLatticeManager.getCollection(tenantId, name);
66
- }
67
-
68
- async createCollection(
69
- request: FastifyRequest,
70
- data: CreateCollectionRequest
71
- ): Promise<Collection> {
72
- const tenantId = getTenantId(request);
73
- const collection = await collectionLatticeManager.registerCollection(tenantId, data);
74
-
75
- try {
76
- await getOrCreateCollectionVectorStore(data.name, data.embeddingKey, tenantId);
77
- } catch (err) {
78
- console.warn(`[CollectionService] Failed to init vector store for ${data.name}:`, err);
79
- }
80
-
81
- return collection;
82
- }
83
-
84
- async updateCollection(
85
- request: FastifyRequest,
86
- name: string,
87
- updates: UpdateCollectionRequest
88
- ): Promise<Collection | null> {
89
- const tenantId = getTenantId(request);
90
- return collectionLatticeManager.updateCollection(tenantId, name, updates);
91
- }
92
-
93
- async deleteCollection(
94
- request: FastifyRequest,
95
- name: string
96
- ): Promise<boolean> {
97
- const tenantId = getTenantId(request);
98
- await removeCollectionVectorStore(name, tenantId);
99
- return collectionLatticeManager.removeCollection(tenantId, name);
100
- }
101
-
102
- // ─── Entry CRUD ───────────────────────────────────────────────
103
-
104
- async getEntries(
105
- request: FastifyRequest,
106
- collectionName: string
107
- ): Promise<EntryResponse[]> {
108
- const collection = await this.getCollectionByName(request, collectionName);
109
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
110
-
111
- const docs = await listCollectionEntries(collectionName, collection.embeddingKey, collection.tenantId);
112
-
113
- return docs.map((doc: Document) => ({
114
- id: (doc.metadata._id as string) || "",
115
- content: doc.pageContent,
116
- metadata: Object.fromEntries(
117
- Object.entries(doc.metadata).filter(([k]) => !k.startsWith("_"))
118
- ),
119
- }));
120
- }
121
-
122
- async createEntry(
123
- request: FastifyRequest,
124
- collectionName: string,
125
- data: { content: string; metadata?: Record<string, unknown> }
126
- ): Promise<EntryResponse> {
127
- const collection = await this.getCollectionByName(request, collectionName);
128
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
129
-
130
- const vectorStore = await getOrCreateCollectionVectorStore(
131
- collectionName, collection.embeddingKey, collection.tenantId
132
- );
133
-
134
- const entryId = uuidv4();
135
- const now = new Date().toISOString();
136
- const doc = new Document({
137
- pageContent: data.content,
138
- metadata: {
139
- _id: entryId,
140
- _created_at: now,
141
- _updated_at: now,
142
- ...(data.metadata || {}),
143
- },
144
- });
145
-
146
- await vectorStore.addDocuments([doc]);
147
-
148
- return { id: entryId, content: data.content, metadata: data.metadata || {} };
149
- }
150
-
151
- async getEntry(
152
- request: FastifyRequest,
153
- collectionName: string,
154
- entryId: string
155
- ): Promise<EntryResponse | null> {
156
- const collection = await this.getCollectionByName(request, collectionName);
157
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
158
-
159
- const docs = await listCollectionEntries(collectionName, collection.embeddingKey, collection.tenantId);
160
- const doc = docs.find((d: Document) => d.metadata._id === entryId);
161
- if (!doc) return null;
162
- return {
163
- id: entryId,
164
- content: doc.pageContent,
165
- metadata: Object.fromEntries(
166
- Object.entries(doc.metadata).filter(([k]) => !k.startsWith("_"))
167
- ),
168
- };
169
- }
170
-
171
- async updateEntry(
172
- request: FastifyRequest,
173
- collectionName: string,
174
- entryId: string,
175
- data: { content?: string; metadata?: Record<string, unknown> }
176
- ): Promise<EntryResponse | null> {
177
- const existing = await this.getEntry(request, collectionName, entryId);
178
- if (!existing) return null;
179
-
180
- const collection = await this.getCollectionByName(request, collectionName);
181
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
182
-
183
- const vectorStore = await getOrCreateCollectionVectorStore(
184
- collectionName, collection.embeddingKey, collection.tenantId
185
- );
186
-
187
- try {
188
- await vectorStore.delete({ filter: { _id: entryId } } as any);
189
- } catch {
190
- // best effort
191
- }
192
-
193
- const now = new Date().toISOString();
194
- const mergedMetadata = { ...existing.metadata, ...(data.metadata || {}) };
195
- const doc = new Document({
196
- pageContent: data.content ?? existing.content,
197
- metadata: { _id: entryId, _created_at: now, _updated_at: now, ...mergedMetadata },
198
- });
199
-
200
- await vectorStore.addDocuments([doc]);
201
-
202
- return { id: entryId, content: data.content ?? existing.content, metadata: mergedMetadata };
203
- }
204
-
205
- async deleteEntry(
206
- request: FastifyRequest,
207
- collectionName: string,
208
- entryId: string
209
- ): Promise<boolean> {
210
- const collection = await this.getCollectionByName(request, collectionName);
211
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
212
-
213
- const vectorStore = await getOrCreateCollectionVectorStore(
214
- collectionName, collection.embeddingKey, collection.tenantId
215
- );
216
-
217
- try {
218
- await vectorStore.delete({ filter: { _id: entryId } } as any);
219
- return true;
220
- } catch {
221
- return false;
222
- }
223
- }
224
-
225
- async searchEntries(
226
- request: FastifyRequest,
227
- collectionName: string,
228
- params: { query: string; filter?: Record<string, unknown>; top_k?: number }
229
- ): Promise<EntryResponse[]> {
230
- const collection = await this.getCollectionByName(request, collectionName);
231
- if (!collection) throw new Error(`Collection "${collectionName}" not found`);
232
-
233
- const vectorStore = await getOrCreateCollectionVectorStore(
234
- collectionName, collection.embeddingKey, collection.tenantId
235
- );
236
-
237
- let embeddings;
238
- try {
239
- embeddings = embeddingsLatticeManager.getEmbeddingsClient(collection.embeddingKey);
240
- } catch {
241
- embeddings = embeddingsLatticeManager.getEmbeddingsClient("default");
242
- }
243
-
244
- const queryVector = await embeddings.embedQuery(params.query);
245
- const results = await vectorStore.similaritySearchVectorWithScore(
246
- queryVector, params.top_k || 5, params.filter as any
247
- );
248
-
249
- return results.map(([doc, score]: [Document, number]) => ({
250
- id: (doc.metadata._id as string) || uuidv4(),
251
- content: doc.pageContent,
252
- metadata: Object.fromEntries(
253
- Object.entries(doc.metadata).filter(([k]) => !k.startsWith("_"))
254
- ),
255
- score,
256
- }));
257
- }
258
- }