@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.
- package/dist/index.js +31 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +31 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -6
- package/.eslintrc.json +0 -22
- package/.turbo/turbo-build.log +0 -46
- package/AGENTS.md +0 -112
- package/CHANGELOG.md +0 -1190
- package/LOGGER_CONFIG.md +0 -135
- package/RESUME_STREAM_CONTENT_BASED.md +0 -326
- package/RESUME_STREAM_README.md +0 -388
- package/jest.config.js +0 -72
- package/public/sdk/README.md +0 -695
- package/public/sdk/dashboard-engine-skill.md +0 -1122
- package/public/sdk/dashboard-single-file-spec.md +0 -357
- package/public/sdk/data-query-sdk-skill.md +0 -307
- package/public/sdk/data-query-sdk.d.ts +0 -252
- package/public/sdk/data-query-sdk.js +0 -970
- package/public/sdk/occupancy-dashboard.html +0 -363
- package/public/sdk/test-dashboard.html +0 -690
- package/scripts/seed-lark-installation.ts +0 -54
- package/src/__tests__/__mocks__/e2b.ts +0 -1
- package/src/__tests__/a2a.test.ts +0 -428
- package/src/__tests__/channel-installations.test.ts +0 -199
- package/src/__tests__/data-query.test.ts +0 -77
- package/src/__tests__/sandbox-provider-registration.test.ts +0 -74
- package/src/__tests__/setup.ts +0 -5
- package/src/__tests__/workspace.test.ts +0 -400
- package/src/channels/__tests__/routes.test.ts +0 -50
- package/src/channels/lark/LarkChannelAdapter.ts +0 -217
- package/src/channels/lark/README.md +0 -187
- package/src/channels/lark/__tests__/controller.test.ts +0 -136
- package/src/channels/lark/__tests__/mapping-service.test.ts +0 -118
- package/src/channels/lark/__tests__/parser.test.ts +0 -72
- package/src/channels/lark/__tests__/sender.test.ts +0 -37
- package/src/channels/lark/__tests__/verification.test.ts +0 -157
- package/src/channels/lark/controller.ts +0 -48
- package/src/channels/lark/mapping-service.ts +0 -138
- package/src/channels/lark/parser.ts +0 -68
- package/src/channels/lark/routes.ts +0 -22
- package/src/channels/lark/sender.ts +0 -58
- package/src/channels/lark/types.ts +0 -20
- package/src/channels/lark/verification.ts +0 -32
- package/src/channels/registry.ts +0 -20
- package/src/channels/routes.ts +0 -30
- package/src/channels/wechat/WechatChannelAdapter.ts +0 -294
- package/src/channels/wechat/__tests__/context-store.test.ts +0 -148
- package/src/channels/wechat/context-store.ts +0 -54
- package/src/channels/wechat/controller.ts +0 -59
- package/src/channels/wechat/routes.ts +0 -7
- package/src/channels/wechat/types.ts +0 -62
- package/src/channels/wechat/wechat-client.ts +0 -162
- package/src/config/local-a2a-templates.ts +0 -59
- package/src/config.ts +0 -124
- package/src/controllers/__tests__/assistant-local-a2a.test.ts +0 -147
- package/src/controllers/__tests__/local-a2a-templates.test.ts +0 -112
- package/src/controllers/__tests__/mime.test.ts +0 -74
- package/src/controllers/__tests__/resources.test.ts +0 -122
- package/src/controllers/__tests__/run.test.ts +0 -115
- package/src/controllers/__tests__/tasks.test.ts +0 -215
- package/src/controllers/__tests__/workflow-tracking.test.ts +0 -113
- package/src/controllers/agent_task.ts +0 -72
- package/src/controllers/assistant.ts +0 -490
- package/src/controllers/auth.ts +0 -524
- package/src/controllers/channel-bindings.ts +0 -135
- package/src/controllers/channel-installations.ts +0 -409
- package/src/controllers/collections.ts +0 -176
- package/src/controllers/config.ts +0 -126
- package/src/controllers/connections.ts +0 -181
- package/src/controllers/data-query.ts +0 -236
- package/src/controllers/database-configs.ts +0 -440
- package/src/controllers/embeddings.ts +0 -22
- package/src/controllers/entries.ts +0 -167
- package/src/controllers/eval.ts +0 -513
- package/src/controllers/export-import.ts +0 -166
- package/src/controllers/health.ts +0 -36
- package/src/controllers/local-a2a-templates.ts +0 -18
- package/src/controllers/local-a2a.ts +0 -149
- package/src/controllers/mcp-configs.ts +0 -673
- package/src/controllers/memory.ts +0 -257
- package/src/controllers/menu-items.ts +0 -114
- package/src/controllers/metrics-configs.ts +0 -1061
- package/src/controllers/middleware-types.ts +0 -15
- package/src/controllers/models.ts +0 -199
- package/src/controllers/personal-assistant.ts +0 -191
- package/src/controllers/resources.ts +0 -477
- package/src/controllers/run.ts +0 -338
- package/src/controllers/sandbox.ts +0 -255
- package/src/controllers/schedules.ts +0 -336
- package/src/controllers/skills.ts +0 -256
- package/src/controllers/tasks.ts +0 -213
- package/src/controllers/tenants.ts +0 -121
- package/src/controllers/thread_status.ts +0 -66
- package/src/controllers/threads.ts +0 -260
- package/src/controllers/tools.ts +0 -139
- package/src/controllers/users.ts +0 -135
- package/src/controllers/workflow-tracking.ts +0 -693
- package/src/controllers/workspace.ts +0 -879
- package/src/export_registrations/a2a-api-key.registration.ts +0 -89
- package/src/export_registrations/agent.registration.ts +0 -80
- package/src/export_registrations/binding.registration.ts +0 -106
- package/src/export_registrations/channel-installation.registration.ts +0 -88
- package/src/export_registrations/collection.registration.ts +0 -85
- package/src/export_registrations/connection.registration.ts +0 -97
- package/src/export_registrations/database-config.registration.ts +0 -94
- package/src/export_registrations/eval.registration.ts +0 -334
- package/src/export_registrations/index.ts +0 -31
- package/src/export_registrations/mcp-config.registration.ts +0 -97
- package/src/export_registrations/menu.registration.ts +0 -91
- package/src/export_registrations/metrics-config.registration.ts +0 -94
- package/src/export_registrations/skill.registration.ts +0 -88
- package/src/export_registrations/task.registration.ts +0 -99
- package/src/index.ts +0 -497
- package/src/logger/Logger.ts +0 -186
- package/src/router/MessageContext.ts +0 -14
- package/src/router/MessageRouter.ts +0 -490
- package/src/router/middlewares/auditLogger.ts +0 -34
- package/src/router/middlewares/deduplication.ts +0 -38
- package/src/router/middlewares/index.ts +0 -3
- package/src/router/middlewares/rateLimit.ts +0 -46
- package/src/routes/__tests__/a2a-test-connection.test.ts +0 -177
- package/src/routes/a2a-bridge.ts +0 -266
- package/src/routes/a2a-test-connection.ts +0 -126
- package/src/routes/a2a.ts +0 -851
- package/src/routes/channel-bindings.ts +0 -11
- package/src/routes/channel-installations.ts +0 -33
- package/src/routes/index.ts +0 -640
- package/src/routes/menu-items.ts +0 -10
- package/src/routes/resource-routes.ts +0 -35
- package/src/routes/stt.ts +0 -102
- package/src/schemas/data-query.ts +0 -69
- package/src/schemas/index.ts +0 -852
- package/src/services/ExportImportService.ts +0 -296
- package/src/services/__tests__/ExportImportService.test.ts +0 -130
- package/src/services/__tests__/eval-runner.test.ts +0 -131
- package/src/services/__tests__/local-a2a.test.ts +0 -124
- package/src/services/agent_task_consumer.ts +0 -348
- package/src/services/collection_service.ts +0 -258
- package/src/services/eval-runner.ts +0 -283
- package/src/services/local-a2a.ts +0 -354
- package/src/services/queue_service.ts +0 -104
- package/src/services/sandbox_service.ts +0 -223
- package/src/services/skill_service.ts +0 -97
- package/src/services/supabase.ts +0 -60
- package/src/swagger.ts +0 -77
- package/src/types/index.ts +0 -118
- package/src/types/koa.d.ts +0 -7
- package/src/utils/__tests__/local-a2a-runtime.test.ts +0 -77
- package/src/utils/__tests__/path-containment.test.ts +0 -35
- package/src/utils/a2a-url.ts +0 -20
- package/src/utils/local-a2a-runtime.ts +0 -107
- package/src/utils/mime.ts +0 -44
- package/src/utils/path-containment.ts +0 -38
- 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
|
-
}
|