@axiom-lattice/gateway 2.1.5 → 2.1.7
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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +19 -0
- package/dist/index.js +103 -275
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +106 -280
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
- package/src/controllers/agent_task.ts +1 -1
- package/src/services/agent_task_consumer.ts +86 -12
- package/src/services/queue_service.ts +70 -10
- package/src/services/AgentManager.ts +0 -46
- package/src/services/agent_task_types.ts +0 -2
- package/src/services/event_bus.ts +0 -62
- package/src/services/queue_service_memory.ts +0 -85
- package/src/services/queue_service_redis.ts +0 -116
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
// Queue service adapter that
|
|
2
|
-
//
|
|
1
|
+
// Queue service adapter that uses QueueLatticeManager from core package
|
|
2
|
+
// Provides backward-compatible API for gateway services
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
queueLatticeManager,
|
|
6
|
+
registerQueueLattice,
|
|
7
|
+
getQueueLattice,
|
|
8
|
+
} from "@axiom-lattice/core";
|
|
9
|
+
import { QueueType, QueueConfig, QueueClient } from "@axiom-lattice/protocols";
|
|
10
|
+
import { RedisQueueClient } from "@axiom-lattice/queue-redis";
|
|
6
11
|
|
|
7
12
|
export type QueueServiceType = "memory" | "redis";
|
|
8
13
|
|
|
14
|
+
// Default queue key
|
|
15
|
+
const DEFAULT_QUEUE_KEY = "default";
|
|
16
|
+
|
|
9
17
|
// Global configuration for queue service type
|
|
10
18
|
// Can be set via environment variable QUEUE_SERVICE_TYPE or via LatticeGateway configuration
|
|
11
19
|
let queueServiceType: QueueServiceType =
|
|
@@ -13,11 +21,45 @@ let queueServiceType: QueueServiceType =
|
|
|
13
21
|
|
|
14
22
|
/**
|
|
15
23
|
* Configure the queue service type
|
|
24
|
+
* This will register or update the default queue service
|
|
16
25
|
* @param type - "memory" or "redis"
|
|
17
26
|
*/
|
|
18
27
|
export const setQueueServiceType = (type: QueueServiceType): void => {
|
|
19
28
|
queueServiceType = type;
|
|
20
29
|
console.log(`Queue service type set to: ${type}`);
|
|
30
|
+
|
|
31
|
+
// Register or update the queue service
|
|
32
|
+
const queueName = process.env.QUEUE_NAME || "tasks";
|
|
33
|
+
const config: QueueConfig = {
|
|
34
|
+
name: "Default Queue Service",
|
|
35
|
+
description: `Default ${type} queue service`,
|
|
36
|
+
type: type === "redis" ? QueueType.REDIS : QueueType.MEMORY,
|
|
37
|
+
queueName,
|
|
38
|
+
options:
|
|
39
|
+
type === "redis"
|
|
40
|
+
? {
|
|
41
|
+
redisUrl: process.env.REDIS_URL,
|
|
42
|
+
redisPassword: process.env.REDIS_PASSWORD,
|
|
43
|
+
}
|
|
44
|
+
: undefined,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Remove existing queue if it exists
|
|
48
|
+
if (queueLatticeManager.hasLattice(DEFAULT_QUEUE_KEY)) {
|
|
49
|
+
queueLatticeManager.removeLattice(DEFAULT_QUEUE_KEY);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create client for Redis type
|
|
53
|
+
let client: QueueClient | undefined;
|
|
54
|
+
if (type === "redis") {
|
|
55
|
+
client = new RedisQueueClient(queueName, {
|
|
56
|
+
redisUrl: process.env.REDIS_URL,
|
|
57
|
+
redisPassword: process.env.REDIS_PASSWORD,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Register the new queue service
|
|
62
|
+
registerQueueLattice(DEFAULT_QUEUE_KEY, config, client);
|
|
21
63
|
};
|
|
22
64
|
|
|
23
65
|
/**
|
|
@@ -27,17 +69,35 @@ export const getQueueServiceType = (): QueueServiceType => {
|
|
|
27
69
|
return queueServiceType;
|
|
28
70
|
};
|
|
29
71
|
|
|
30
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Get the default queue service
|
|
74
|
+
* If not registered, register it with the current configuration
|
|
75
|
+
*/
|
|
31
76
|
const getQueueService = () => {
|
|
32
|
-
|
|
77
|
+
// Check if queue is already registered
|
|
78
|
+
if (!queueLatticeManager.hasLattice(DEFAULT_QUEUE_KEY)) {
|
|
79
|
+
// Auto-register with current configuration
|
|
80
|
+
setQueueServiceType(queueServiceType);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return getQueueLattice(DEFAULT_QUEUE_KEY);
|
|
33
84
|
};
|
|
34
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Push agent task to queue
|
|
88
|
+
* @param agentTask - Agent task to push
|
|
89
|
+
*/
|
|
35
90
|
export const pushAgentTaskToQueue = async (agentTask: any) => {
|
|
36
|
-
const
|
|
37
|
-
|
|
91
|
+
const queue = getQueueService();
|
|
92
|
+
const result = await queue.push(agentTask);
|
|
93
|
+
return result;
|
|
38
94
|
};
|
|
39
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Pop agent task from queue
|
|
98
|
+
*/
|
|
40
99
|
export const popAgentTaskFromQueue = async () => {
|
|
41
|
-
const
|
|
42
|
-
|
|
100
|
+
const queue = getQueueService();
|
|
101
|
+
const result = await queue.pop();
|
|
102
|
+
return result;
|
|
43
103
|
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { AGENT_TASK_EVENT } from "./agent_task_types";
|
|
2
|
-
import eventBus from "./event_bus";
|
|
3
|
-
|
|
4
|
-
export class AgentManager {
|
|
5
|
-
private static instance: AgentManager;
|
|
6
|
-
private constructor() {}
|
|
7
|
-
private agents: { name: string; agent: any }[] = [];
|
|
8
|
-
public static getInstance(): AgentManager {
|
|
9
|
-
if (!AgentManager.instance) {
|
|
10
|
-
AgentManager.instance = new AgentManager();
|
|
11
|
-
}
|
|
12
|
-
return AgentManager.instance;
|
|
13
|
-
}
|
|
14
|
-
callAgentInQueue(queue: {
|
|
15
|
-
assistant_id: string;
|
|
16
|
-
input?: any;
|
|
17
|
-
thread_id: string;
|
|
18
|
-
command?: any;
|
|
19
|
-
"x-tenant-id"?: string;
|
|
20
|
-
}) {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
//const callback_event = `${queue.assistant_id}::${queue.thread_id}`;
|
|
23
|
-
// eventBus.subscribeOnce(callback_event, (data) => {
|
|
24
|
-
// if (data.success) {
|
|
25
|
-
// console.log("AgentManager callAgentInQueue success", data);
|
|
26
|
-
// resolve(data.result);
|
|
27
|
-
// } else {
|
|
28
|
-
// console.log("AgentManager callAgentInQueue error", data);
|
|
29
|
-
// reject(data.error);
|
|
30
|
-
// }
|
|
31
|
-
// });
|
|
32
|
-
try {
|
|
33
|
-
eventBus.publish(
|
|
34
|
-
AGENT_TASK_EVENT,
|
|
35
|
-
{
|
|
36
|
-
...queue,
|
|
37
|
-
},
|
|
38
|
-
true
|
|
39
|
-
);
|
|
40
|
-
resolve(true);
|
|
41
|
-
} catch (error) {
|
|
42
|
-
reject(error);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
import { pushAgentTaskToQueue } from "./queue_service";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 事件总线服务
|
|
6
|
-
* 用于系统内部组件间的事件发布与订阅
|
|
7
|
-
*/
|
|
8
|
-
class EventBus {
|
|
9
|
-
private emitter: EventEmitter;
|
|
10
|
-
|
|
11
|
-
constructor() {
|
|
12
|
-
this.emitter = new EventEmitter();
|
|
13
|
-
// 设置最大监听器数量,避免内存泄漏警告
|
|
14
|
-
this.emitter.setMaxListeners(100);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 发布事件
|
|
19
|
-
* @param eventName 事件名称
|
|
20
|
-
* @param data 事件数据
|
|
21
|
-
*/
|
|
22
|
-
publish(eventName: string, data: any, useQueue: boolean = false): void {
|
|
23
|
-
//console.log(`发布事件: ${eventName}`, data);
|
|
24
|
-
if (useQueue) {
|
|
25
|
-
pushAgentTaskToQueue(data);
|
|
26
|
-
} else {
|
|
27
|
-
this.emitter.emit(eventName, data);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 订阅事件
|
|
33
|
-
* @param eventName 事件名称
|
|
34
|
-
* @param callback 回调函数
|
|
35
|
-
*/
|
|
36
|
-
subscribe(eventName: string, callback: (data: any) => void): void {
|
|
37
|
-
this.emitter.on(eventName, callback);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 取消订阅事件
|
|
42
|
-
* @param eventName 事件名称
|
|
43
|
-
* @param callback 回调函数
|
|
44
|
-
*/
|
|
45
|
-
unsubscribe(eventName: string, callback: (data: any) => void): void {
|
|
46
|
-
this.emitter.off(eventName, callback);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 只订阅一次事件
|
|
51
|
-
* @param eventName 事件名称
|
|
52
|
-
* @param callback 回调函数
|
|
53
|
-
*/
|
|
54
|
-
subscribeOnce(eventName: string, callback: (data: any) => void): void {
|
|
55
|
-
this.emitter.once(eventName, callback);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// 创建单例实例
|
|
60
|
-
const eventBus = new EventBus();
|
|
61
|
-
|
|
62
|
-
export default eventBus;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// In-memory queue service implementation
|
|
2
|
-
// This is a memory-based alternative to the Redis queue service
|
|
3
|
-
|
|
4
|
-
const queue_name = process.env.QUEUE_NAME || "tasks"; // Queue name, local development needs to configure its own queue
|
|
5
|
-
|
|
6
|
-
// In-memory storage for queues: Map<queue_name, message[]>
|
|
7
|
-
// Using Map to support multiple queues (e.g., per tenant)
|
|
8
|
-
const queues = new Map<string, any[]>();
|
|
9
|
-
|
|
10
|
-
// Initialize queue if it doesn't exist
|
|
11
|
-
const ensureQueue = (queueName: string): void => {
|
|
12
|
-
if (!queues.has(queueName)) {
|
|
13
|
-
queues.set(queueName, []);
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// Enqueue Message (equivalent to lPush - push to left/beginning)
|
|
18
|
-
const sendToQueue = async (queueName: string, message: any) => {
|
|
19
|
-
try {
|
|
20
|
-
ensureQueue(queueName);
|
|
21
|
-
const queue = queues.get(queueName)!;
|
|
22
|
-
|
|
23
|
-
// lPush behavior: add to the beginning of the array
|
|
24
|
-
queue.unshift(message);
|
|
25
|
-
|
|
26
|
-
const result = queue.length;
|
|
27
|
-
console.log("lPush (memory)", result);
|
|
28
|
-
return { data: result, error: null };
|
|
29
|
-
} catch (error) {
|
|
30
|
-
console.error(error);
|
|
31
|
-
return { data: null, error };
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// Dequeue Message (equivalent to rPop - pop from right/end)
|
|
36
|
-
const popFromQueue = async (queueName: string) => {
|
|
37
|
-
try {
|
|
38
|
-
ensureQueue(queueName);
|
|
39
|
-
const queue = queues.get(queueName)!;
|
|
40
|
-
|
|
41
|
-
// rPop behavior: remove from the end of the array
|
|
42
|
-
// This creates FIFO behavior when combined with lPush (unshift + pop = FIFO)
|
|
43
|
-
const message = queue.pop();
|
|
44
|
-
|
|
45
|
-
if (message) {
|
|
46
|
-
return { data: message, error: null };
|
|
47
|
-
}
|
|
48
|
-
return { data: null, error: null };
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error(error);
|
|
51
|
-
return { data: null, error };
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const createTenantQueue = async () => {
|
|
56
|
-
// Initialize the queue in memory
|
|
57
|
-
try {
|
|
58
|
-
ensureQueue(queue_name);
|
|
59
|
-
const queue = queues.get(queue_name)!;
|
|
60
|
-
const exists = queue !== undefined;
|
|
61
|
-
return { success: true, queue_name };
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error(error);
|
|
64
|
-
return { success: false, error };
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const pushAgentTaskToQueue = async (agentTask: any) => {
|
|
69
|
-
const tenantId = agentTask["x-tenant-id"];
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
await createTenantQueue();
|
|
73
|
-
const result = await sendToQueue(`${queue_name}`, agentTask);
|
|
74
|
-
return result;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.error(error);
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const popAgentTaskFromQueue = async () => {
|
|
82
|
-
const result = await popFromQueue(`${queue_name}`);
|
|
83
|
-
return result;
|
|
84
|
-
};
|
|
85
|
-
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { createClient, RedisClientType } from "redis";
|
|
2
|
-
|
|
3
|
-
// Redis queue service implementation
|
|
4
|
-
// This is a Redis-based queue service
|
|
5
|
-
|
|
6
|
-
const queue_name = process.env.QUEUE_NAME || "tasks"; // Queue name, local development needs to configure its own queue
|
|
7
|
-
|
|
8
|
-
// Redis client - initialized lazily only when needed
|
|
9
|
-
let redisClient: RedisClientType | null = null;
|
|
10
|
-
let isConnecting = false;
|
|
11
|
-
let connectionPromise: Promise<void> | null = null;
|
|
12
|
-
|
|
13
|
-
// Lazy initialization of Redis client
|
|
14
|
-
const getRedisClient = async (): Promise<RedisClientType> => {
|
|
15
|
-
// If client is already connected, return it
|
|
16
|
-
if (redisClient?.isOpen) {
|
|
17
|
-
return redisClient;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// If connection is in progress, wait for it
|
|
21
|
-
if (isConnecting && connectionPromise) {
|
|
22
|
-
await connectionPromise;
|
|
23
|
-
if (redisClient?.isOpen) {
|
|
24
|
-
return redisClient;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Create and connect to Redis client
|
|
29
|
-
isConnecting = true;
|
|
30
|
-
connectionPromise = (async () => {
|
|
31
|
-
try {
|
|
32
|
-
const redisOptions: any = {
|
|
33
|
-
url: process.env.REDIS_URL || "redis://localhost:6379",
|
|
34
|
-
password: process.env.REDIS_PASSWORD,
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
redisClient = createClient(redisOptions) as RedisClientType;
|
|
38
|
-
|
|
39
|
-
redisClient.on("error", (err: Error) =>
|
|
40
|
-
console.error("Redis Client Error", err)
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
await redisClient.connect();
|
|
44
|
-
console.log("Redis connection successful");
|
|
45
|
-
isConnecting = false;
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.error("Redis connection failed:", error);
|
|
48
|
-
isConnecting = false;
|
|
49
|
-
throw error;
|
|
50
|
-
}
|
|
51
|
-
})();
|
|
52
|
-
|
|
53
|
-
await connectionPromise;
|
|
54
|
-
return redisClient!;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// Enqueue Message
|
|
58
|
-
const sendToQueue = async (queueName: string, message: any) => {
|
|
59
|
-
try {
|
|
60
|
-
const client = await getRedisClient();
|
|
61
|
-
// Push message to queue
|
|
62
|
-
const result = await client.lPush(queueName, JSON.stringify(message));
|
|
63
|
-
console.log("lPush", result);
|
|
64
|
-
return { data: result, error: null };
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error(error);
|
|
67
|
-
return { data: null, error };
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Dequeue Message
|
|
72
|
-
const popFromQueue = async (queueName: string) => {
|
|
73
|
-
try {
|
|
74
|
-
const client = await getRedisClient();
|
|
75
|
-
// Get message from queue
|
|
76
|
-
const message = await client.rPop(queueName);
|
|
77
|
-
if (message) {
|
|
78
|
-
return { data: JSON.parse(message), error: null };
|
|
79
|
-
}
|
|
80
|
-
return { data: null, error: null };
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error(error);
|
|
83
|
-
return { data: null, error };
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const createTenantQueue = async () => {
|
|
88
|
-
// Redis doesn't need explicit queue creation, but we keep this function for API compatibility
|
|
89
|
-
// Can perform some initialization operations, such as checking if queue exists
|
|
90
|
-
try {
|
|
91
|
-
const client = await getRedisClient();
|
|
92
|
-
const exists = await client.exists(queue_name);
|
|
93
|
-
return { success: true, queue_name };
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error(error);
|
|
96
|
-
return { success: false, error };
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export const pushAgentTaskToQueue = async (agentTask: any) => {
|
|
101
|
-
const tenantId = agentTask["x-tenant-id"];
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
await createTenantQueue();
|
|
105
|
-
const result = await sendToQueue(`${queue_name}`, agentTask);
|
|
106
|
-
return result;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error(error);
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export const popAgentTaskFromQueue = async () => {
|
|
114
|
-
const result = await popFromQueue(`${queue_name}`);
|
|
115
|
-
return result;
|
|
116
|
-
};
|