@axiom-lattice/gateway 2.1.44 → 2.1.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiom-lattice/gateway",
3
- "version": "2.1.44",
3
+ "version": "2.1.45",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -35,16 +35,19 @@
35
35
  "pino": "^9.7.0",
36
36
  "pino-pretty": "^13.0.0",
37
37
  "pino-roll": "^3.1.0",
38
+ "pg": "^8.11.0",
38
39
  "redis": "^5.0.1",
39
40
  "uuid": "^9.0.1",
40
- "@axiom-lattice/core": "2.1.38",
41
- "@axiom-lattice/protocols": "2.1.20",
42
- "@axiom-lattice/queue-redis": "1.0.19"
41
+ "@axiom-lattice/core": "2.1.39",
42
+ "@axiom-lattice/pg-stores": "1.0.29",
43
+ "@axiom-lattice/protocols": "2.1.21",
44
+ "@axiom-lattice/queue-redis": "1.0.20"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/jest": "^29.5.14",
46
48
  "@types/lodash": "^4.17.16",
47
49
  "@types/node": "^20.19.13",
50
+ "@types/pg": "^8.11.0",
48
51
  "@types/uuid": "^9.0.8",
49
52
  "@types/ws": "^8.18.1",
50
53
  "@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -1,6 +1,5 @@
1
1
  import { FastifyRequest, FastifyReply } from "fastify";
2
- import { draw_graph } from "../services/agent_service";
3
- import { getStoreLattice } from "@axiom-lattice/core";
2
+ import { agentInstanceManager, getStoreLattice } from "@axiom-lattice/core";
4
3
  import type {
5
4
  Assistant,
6
5
  CreateAssistantRequest,
@@ -26,7 +25,7 @@ function getTenantId(request: FastifyRequest): string {
26
25
  if (userTenantId) {
27
26
  return userTenantId;
28
27
  }
29
-
28
+
30
29
  // Fallback to request headers for backward compatibility
31
30
  return (request.headers["x-tenant-id"] as string) || "default";
32
31
  }
@@ -321,8 +320,10 @@ export const getAgentGraph = async (
321
320
  const { assistantId } = request.params;
322
321
  const tenant_id = getTenantId(request);
323
322
 
323
+ const agent = agentInstanceManager.getAgent({ assistant_id: assistantId, tenant_id, thread_id: '' })
324
+
324
325
  // Call drawing service to get image data
325
- const imageData = await draw_graph(assistantId, tenant_id);
326
+ const imageData = await agent.get_draw_graph()
326
327
 
327
328
  // Set response header and return image data
328
329
  reply.header("Content-Type", "application/json").send({
@@ -1,5 +1,5 @@
1
1
  import { FastifyRequest, FastifyReply } from "fastify";
2
- import { agent_messages, agent_state } from "../services/agent_service";
2
+ import { agentInstanceManager } from "@axiom-lattice/core";
3
3
 
4
4
  // 设置内存项
5
5
  export const setMemoryItem = async (
@@ -108,11 +108,9 @@ export const getAllMemoryItems = async (
108
108
  return;
109
109
  }
110
110
 
111
- const result = await agent_messages({
112
- assistant_id: assistantId,
113
- thread_id: thread_id,
114
- tenant_id: tenant_id,
115
- });
111
+ const agent = agentInstanceManager.getAgent({ assistant_id: assistantId, tenant_id, thread_id: thread_id })
112
+
113
+ const result = await agent.getCurrentMessages();
116
114
 
117
115
  if (!result) {
118
116
  reply.status(500).send(result);
@@ -156,19 +154,25 @@ export const getAgentState = async (
156
154
  }
157
155
 
158
156
  const tenant_id = request.headers["x-tenant-id"] as string;
159
-
160
- const result = await agent_state({
161
- assistant_id: assistantId,
162
- thread_id: thread_id,
163
- tenant_id: tenant_id,
164
- });
157
+ const agent = agentInstanceManager.getAgent({ assistant_id: assistantId, tenant_id, thread_id: thread_id })
158
+
159
+ // 1. 获取 LangGraph 状态(现有逻辑)
160
+ const result = await agent.getCurrentState();
161
+ const pendingMessages = await agent.getPendingMessages();
162
+
165
163
 
166
164
  if (!result) {
167
165
  reply.status(500).send(result);
168
166
  return;
169
167
  }
170
168
 
171
- reply.send(result);
169
+ // 3. 合并返回
170
+ const mergedResult = {
171
+ ...result,
172
+ pendingMessages
173
+ };
174
+
175
+ reply.send(mergedResult);
172
176
  } catch (error: any) {
173
177
  reply.status(500).send({
174
178
  success: false,
@@ -1,7 +1,12 @@
1
1
  import { FastifyRequest, FastifyReply } from "fastify";
2
- import * as agentService from "../services/agent_service";
3
2
  import { CreateRunRequest } from "../types";
4
3
  import { v4 } from "uuid";
4
+ import {
5
+ Agent,
6
+ ThreadStatus,
7
+ agentLatticeManager,
8
+ agentInstanceManager,
9
+ } from "@axiom-lattice/core";
5
10
 
6
11
  interface ResumeStreamRequest {
7
12
  thread_id: string;
@@ -10,7 +15,7 @@ interface ResumeStreamRequest {
10
15
  poll_interval?: number;
11
16
  }
12
17
 
13
- // 创建运行
18
+ // Create run
14
19
  export const createRun = async (
15
20
  request: FastifyRequest,
16
21
  reply: FastifyReply
@@ -31,7 +36,7 @@ export const createRun = async (
31
36
  const project_id = request.headers["x-project-id"] as string;
32
37
  const x_request_id = (request.headers["x-request-id"] as string) || v4();
33
38
 
34
- // 验证请求数据
39
+ // Validate request
35
40
  if (!assistant_id) {
36
41
  reply.status(400).send({
37
42
  success: false,
@@ -40,35 +45,21 @@ export const createRun = async (
40
45
  return;
41
46
  }
42
47
 
43
- // 如果请求streaming,则agent_stream
44
- if (streaming) {
45
- // 先检查agent是否存在(在hijack之前)
46
- const agentExists = await agentService.checkAgentExists(tenant_id, assistant_id);
47
- if (!agentExists) {
48
- reply.status(404).send({
49
- success: false,
50
- error: `Agent ${assistant_id} not found for tenant ${tenant_id}`,
51
- });
52
- return;
53
- }
54
-
55
- // 开始运行
56
- const stream = await agentService.agent_stream({
57
- assistant_id: assistant_id,
58
- input: input,
59
- thread_id: thread_id,
60
- command,
61
- tenant_id: tenant_id,
62
- workspace_id: workspace_id,
63
- project_id: project_id,
64
- run_id: x_request_id,
65
- custom_run_config,
66
- });
48
+ // Get or create Agent instance (ensures single instance per thread)
49
+ const agent = agentInstanceManager.getAgent({
50
+ assistant_id,
51
+ thread_id,
52
+ tenant_id,
53
+ workspace_id,
54
+ project_id,
55
+ custom_run_config,
56
+ });
67
57
 
68
- // 通知 Fastify 我们将手动处理响应
69
- reply.hijack();
70
58
 
71
- // 设置 SSE 响应头
59
+ // Handle streaming requests
60
+ if (streaming) {
61
+ // Setup SSE
62
+ reply.hijack();
72
63
  reply.raw.writeHead(200, {
73
64
  "Content-Type": "text/event-stream",
74
65
  "Cache-Control": "no-cache",
@@ -77,41 +68,57 @@ export const createRun = async (
77
68
  });
78
69
 
79
70
  try {
80
- let chunkCount = 0;
71
+
72
+ // Execute agent with streaming
73
+ const result = await agent.addMessage({
74
+ input,
75
+ command,
76
+ });
77
+
78
+ // const agentStatus = await agent.getRunStatus()
79
+ // console.log(agentStatus)
80
+ // if (agentStatus === "busy") {
81
+ // reply.status(200).send({
82
+ // success: true,
83
+
84
+ // });
85
+ // return
86
+ // }
87
+
88
+ const stream = agent.chunkStream((result).messageId)
89
+
90
+ // Forward all chunks to SSE
81
91
  for await (const chunk of stream) {
82
- chunkCount++;
92
+ console.log(input.message, chunk.data.content);
83
93
  const success = reply.raw.write(`data: ${JSON.stringify(chunk)}\n\n`);
84
94
  if (!success) {
85
95
  await new Promise(resolve => reply.raw.once('drain', resolve));
86
96
  }
87
97
  }
88
98
  } catch (error: any) {
89
- // Send error as SSE event before closing (following MessageChunk format)
99
+ // Send error as SSE event
90
100
  const errorEvent = {
91
101
  type: 'error',
92
102
  data: {
93
103
  id: v4(),
94
- content: error.message || 'Stream processing error'
95
- }
104
+ content: error.message || 'Stream processing error',
105
+ },
96
106
  };
97
107
  reply.raw.write(`data: ${JSON.stringify(errorEvent)}\n\n`);
98
108
  } finally {
99
109
  reply.raw.end();
100
110
  }
101
111
  } else {
102
- // 后台运行的情况
103
- const result = await agentService.agent_invoke({
104
- assistant_id: assistant_id,
105
- input: input,
106
- command: command,
107
- thread_id: thread_id,
108
- tenant_id: tenant_id,
109
- workspace_id: workspace_id,
110
- project_id: project_id,
111
- run_id: x_request_id,
112
- custom_run_config,
112
+ // Non-streaming: use agentExecutor
113
+ const { message: msg, ...restInputNonStream } = input;
114
+ const result = await agent.invoke({
115
+ input: { message: msg, ...restInputNonStream },
116
+ command,
117
+ });
118
+ reply.status(200).send({
119
+ success: true,
120
+ ...result,
113
121
  });
114
- reply.status(200).send(result);
115
122
  }
116
123
  } catch (error: any) {
117
124
  reply.status(500).send({
@@ -151,14 +158,17 @@ export const resumeStream = async (
151
158
  });
152
159
 
153
160
  try {
154
- // Get the stream from agent service
155
- const stream = await agentService.resume_stream({
161
+ // Create Agent instance for accessing chunk buffer
162
+ // Note: assistant_id, tenant_id are not required for chunkStream
163
+ const agent = new Agent({
164
+ assistant_id: '',
156
165
  thread_id,
157
- message_id,
158
- known_content: known_content,
159
- poll_interval: poll_interval || 100,
166
+ tenant_id: '',
160
167
  });
161
168
 
169
+ // Get the stream from agent's chunk buffer
170
+ const stream = agent.chunkStream(message_id, known_content);
171
+
162
172
  // Stream the chunks to the client
163
173
  for await (const chunk of stream) {
164
174
  reply.raw.write(`data: ${JSON.stringify(chunk)}\n\n`);
@@ -0,0 +1,228 @@
1
+ // import { FastifyRequest, FastifyReply } from "fastify";
2
+ // import { QueueMode } from "@axiom-lattice/core";
3
+
4
+
5
+ // /**
6
+ // * GET /api/threads/:thread_id/status
7
+ // * Query single thread status
8
+ // */
9
+ // export async function getThreadStatusHandler(
10
+ // request: FastifyRequest,
11
+ // reply: FastifyReply
12
+ // ) {
13
+ // try {
14
+ // const { thread_id } = request.params as { thread_id: string };
15
+ // const tenant_id = request.headers["x-tenant-id"] as string;
16
+
17
+ // if (!tenant_id) {
18
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
19
+ // }
20
+
21
+ // const state = lifecycleManager.getThreadStatus(tenant_id, thread_id);
22
+
23
+ // if (!state) {
24
+ // return reply.code(404).send({
25
+ // error: "Thread not found",
26
+ // threadId: thread_id,
27
+ // });
28
+ // }
29
+
30
+ // return reply.send(state);
31
+ // } catch (error) {
32
+ // console.error("Error getting thread status:", error);
33
+ // return reply.code(500).send({
34
+ // error: "Internal server error",
35
+ // message: error instanceof Error ? error.message : String(error),
36
+ // });
37
+ // }
38
+ // }
39
+
40
+ // /**
41
+ // * GET /api/assistants/:assistant_id/threads/status
42
+ // * Query all threads status for an agent
43
+ // */
44
+ // export async function getAgentThreadsHandler(
45
+ // request: FastifyRequest,
46
+ // reply: FastifyReply
47
+ // ) {
48
+ // try {
49
+ // const { assistant_id } = request.params as { assistant_id: string };
50
+ // const tenant_id = request.headers["x-tenant-id"] as string;
51
+
52
+ // if (!tenant_id) {
53
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
54
+ // }
55
+
56
+ // const threads = lifecycleManager.getAgentThreads(tenant_id, assistant_id);
57
+
58
+ // return reply.send({
59
+ // assistantId: assistant_id,
60
+ // threads,
61
+ // count: threads.length,
62
+ // });
63
+ // } catch (error) {
64
+ // console.error("Error getting agent threads:", error);
65
+ // return reply.code(500).send({
66
+ // error: "Internal server error",
67
+ // message: error instanceof Error ? error.message : String(error),
68
+ // });
69
+ // }
70
+ // }
71
+
72
+ // /**
73
+ // * GET /api/threads/active
74
+ // * Query all active threads (BUSY + INTERRUPTED)
75
+ // */
76
+ // export async function getActiveThreadsHandler(
77
+ // request: FastifyRequest,
78
+ // reply: FastifyReply
79
+ // ) {
80
+ // try {
81
+ // const tenant_id = request.headers["x-tenant-id"] as string;
82
+
83
+ // if (!tenant_id) {
84
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
85
+ // }
86
+
87
+ // const threads = lifecycleManager.getActiveThreads(tenant_id);
88
+
89
+ // return reply.send({
90
+ // threads,
91
+ // count: threads.length,
92
+ // });
93
+ // } catch (error) {
94
+ // console.error("Error getting active threads:", error);
95
+ // return reply.code(500).send({
96
+ // error: "Internal server error",
97
+ // message: error instanceof Error ? error.message : String(error),
98
+ // });
99
+ // }
100
+ // }
101
+
102
+ // /**
103
+ // * POST /api/threads/:thread_id/messages
104
+ // * Add message to queue or execute immediately (steer mode)
105
+ // */
106
+ // export async function addMessageHandler(
107
+ // request: FastifyRequest,
108
+ // reply: FastifyReply
109
+ // ) {
110
+ // try {
111
+ // const { thread_id } = request.params as { thread_id: string };
112
+ // const tenant_id = request.headers["x-tenant-id"] as string;
113
+ // const { assistant_id, content, mode } = request.body as {
114
+ // assistant_id: string;
115
+ // content: any;
116
+ // mode?: QueueMode;
117
+ // };
118
+
119
+ // if (!tenant_id) {
120
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
121
+ // }
122
+
123
+ // if (!assistant_id || !content) {
124
+ // return reply.code(400).send({ error: "Missing assistant_id or content" });
125
+ // }
126
+
127
+ // const result = await lifecycleManager.addMessage(
128
+ // tenant_id,
129
+ // assistant_id,
130
+ // thread_id,
131
+ // content,
132
+ // mode
133
+ // );
134
+
135
+ // return reply.send({
136
+ // success: true,
137
+ // threadId: thread_id,
138
+ // ...result,
139
+ // });
140
+ // } catch (error) {
141
+ // console.error("Error adding message:", error);
142
+ // return reply.code(500).send({
143
+ // error: "Internal server error",
144
+ // message: error instanceof Error ? error.message : String(error),
145
+ // });
146
+ // }
147
+ // }
148
+
149
+ // /**
150
+ // * DELETE /api/threads/:thread_id/messages/:message_id
151
+ // * Remove pending message
152
+ // */
153
+ // export async function removeMessageHandler(
154
+ // request: FastifyRequest,
155
+ // reply: FastifyReply
156
+ // ) {
157
+ // try {
158
+ // const { thread_id, message_id } = request.params as {
159
+ // thread_id: string;
160
+ // message_id: string;
161
+ // };
162
+ // const tenant_id = request.headers["x-tenant-id"] as string;
163
+
164
+ // if (!tenant_id) {
165
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
166
+ // }
167
+
168
+ // const success = await lifecycleManager.removePendingMessage(
169
+ // tenant_id,
170
+ // thread_id,
171
+ // message_id
172
+ // );
173
+
174
+ // if (!success) {
175
+ // return reply.code(404).send({
176
+ // error: "Message not found",
177
+ // messageId: message_id,
178
+ // });
179
+ // }
180
+
181
+ // return reply.send({
182
+ // success: true,
183
+ // messageId: message_id,
184
+ // });
185
+ // } catch (error) {
186
+ // console.error("Error removing message:", error);
187
+ // return reply.code(500).send({
188
+ // error: "Internal server error",
189
+ // message: error instanceof Error ? error.message : String(error),
190
+ // });
191
+ // }
192
+ // }
193
+
194
+ // /**
195
+ // * PUT /api/threads/:thread_id/queue-config
196
+ // * Update queue configuration
197
+ // */
198
+ // export async function updateQueueConfigHandler(
199
+ // request: FastifyRequest,
200
+ // reply: FastifyReply
201
+ // ) {
202
+ // try {
203
+ // const { thread_id } = request.params as { thread_id: string };
204
+ // const tenant_id = request.headers["x-tenant-id"] as string;
205
+ // const config = request.body as {
206
+ // mode?: QueueMode;
207
+ // maxSize?: number;
208
+ // };
209
+
210
+ // if (!tenant_id) {
211
+ // return reply.code(400).send({ error: "Missing x-tenant-id header" });
212
+ // }
213
+
214
+ // await lifecycleManager.setQueueConfig(tenant_id, thread_id, config);
215
+
216
+ // return reply.send({
217
+ // success: true,
218
+ // threadId: thread_id,
219
+ // config,
220
+ // });
221
+ // } catch (error) {
222
+ // console.error("Error updating queue config:", error);
223
+ // return reply.code(500).send({
224
+ // error: "Internal server error",
225
+ // message: error instanceof Error ? error.message : String(error),
226
+ // });
227
+ // }
228
+ // }
package/src/index.ts CHANGED
@@ -116,7 +116,7 @@ app.addHook("onResponse", (request, reply, done) => {
116
116
  "x-tenant-id": getHeaderValue(request.headers["x-tenant-id"]),
117
117
  "x-request-id": getHeaderValue(request.headers["x-request-id"]),
118
118
  };
119
- loggerLattice.info(`${request.method} ${request.url} - ${reply.statusCode}`);
119
+ //loggerLattice.info(`${request.method} ${request.url} - ${reply.statusCode}`);
120
120
  done();
121
121
  });
122
122
 
@@ -244,6 +244,13 @@ const start = async (config?: LatticeGatewayConfig) => {
244
244
  await app.listen({ port: target_port, host: "0.0.0.0" });
245
245
  logger.info(`Lattice Gateway is running on port: ${target_port}`);
246
246
 
247
+ // Initialize AgentLifecycleManager
248
+ try {
249
+ logger.info("AgentLifecycleManager initialized");
250
+ } catch (error) {
251
+ logger.warn("Failed to initialize AgentLifecycleManager", { error });
252
+ }
253
+
247
254
  // Configure queue service
248
255
  const queueServiceConfig = config?.queueServiceConfig;
249
256
  if (queueServiceConfig) {
@@ -38,6 +38,14 @@ import { registerMcpServerConfigRoutes } from "../controllers/mcp-configs";
38
38
  import { registerUserRoutes } from "../controllers/users";
39
39
  import { registerTenantRoutes } from "../controllers/tenants";
40
40
  import { registerAuthRoutes } from "../controllers/auth";
41
+ // import {
42
+ // getThreadStatusHandler,
43
+ // getAgentThreadsHandler,
44
+ // getActiveThreadsHandler,
45
+ // addMessageHandler,
46
+ // removeMessageHandler,
47
+ // updateQueueConfigHandler,
48
+ // } from "../controllers/thread_status";
41
49
 
42
50
  export const registerLatticeRoutes = (app: FastifyInstance): void => {
43
51
  // 运行路由
@@ -328,4 +336,14 @@ export const registerLatticeRoutes = (app: FastifyInstance): void => {
328
336
  autoApproveUsers: process.env.AUTO_APPROVE_USERS !== "false",
329
337
  allowTenantRegistration: process.env.ALLOW_TENANT_REGISTRATION !== "false",
330
338
  });
339
+
340
+ // // Thread 状态查询路由
341
+ // app.get("/api/threads/:thread_id/status", getThreadStatusHandler);
342
+ // app.get("/api/assistants/:assistant_id/threads/status", getAgentThreadsHandler);
343
+ // app.get("/api/threads/active", getActiveThreadsHandler);
344
+
345
+ // // Thread 消息队列路由
346
+ // app.post("/api/threads/:thread_id/messages", addMessageHandler);
347
+ // app.delete("/api/threads/:thread_id/messages/:message_id", removeMessageHandler);
348
+ // app.put("/api/threads/:thread_id/queue-config", updateQueueConfigHandler);
331
349
  };