@myassis/gateway 1.0.30 → 1.0.32

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.
@@ -261,8 +261,11 @@ router.post('/:id/sessions', ensureAgentManager, async (req, res) => {
261
261
  success: true,
262
262
  data: {
263
263
  id: session.id,
264
+ agentId: session.agentId,
264
265
  title: session.title,
265
266
  selectModelId: session.selectModelId,
267
+ messageQueue: session.messageQueue,
268
+ messageQueueAutoExecute: session.messageQueueAutoExecute,
266
269
  createdAt: session.createdAt,
267
270
  updatedAt: session.updatedAt,
268
271
  }
@@ -285,14 +288,17 @@ router.put('/:id/sessions/:sessionId', ensureAgentManager, async (req, res) => {
285
288
  if (!agent) {
286
289
  return res.status(404).json({ success: false, error: 'Agent not found' });
287
290
  }
288
- const { title, selectModelId, unreadCount } = req.body;
289
- const session = agent.updateSession(req.params.sessionId, { title, selectModelId, unreadCount });
291
+ const { title, selectModelId, unreadCount, messageQueue, messageQueueAutoExecute } = req.body;
292
+ const session = agent.updateSession(req.params.sessionId, { title, selectModelId, unreadCount, messageQueue, messageQueueAutoExecute });
290
293
  res.json({
291
294
  success: true,
292
295
  data: {
293
296
  id: session.id,
297
+ agentId: session.agentId,
294
298
  title: session.title,
295
299
  selectModelId: session.selectModelId,
300
+ messageQueue: session.messageQueue,
301
+ messageQueueAutoExecute: session.messageQueueAutoExecute,
296
302
  createdAt: session.createdAt,
297
303
  updatedAt: session.updatedAt,
298
304
  }
@@ -252,6 +252,8 @@ class AgentManager {
252
252
  unreadCount: s.unreadCount,
253
253
  createdAt: s.createdAt,
254
254
  updatedAt: s.updatedAt,
255
+ messageQueue: s.messageQueue,
256
+ messageQueueAutoExecute: s.messageQueueAutoExecute
255
257
  }));
256
258
  }
257
259
  /**
@@ -12,6 +12,13 @@ const DEFAULT_CONFIG = {
12
12
  summaryThreshold: 10,
13
13
  enabled: true,
14
14
  };
15
+ /** SSE 辅助方法:res 为 null 时跳过写入(本地执行模式) */
16
+ const sendSSE = (res, data) => {
17
+ if (!res)
18
+ return;
19
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
20
+ res.flush?.();
21
+ };
15
22
  /**
16
23
  * 记忆管理器
17
24
  * 实现总结式记忆:当对话超过一定长度时,自动生成对话摘要
@@ -21,10 +28,12 @@ class MemoryManager {
21
28
  signal;
22
29
  config = DEFAULT_CONFIG;
23
30
  childAgent;
24
- constructor(session, signal, childAgent) {
31
+ res;
32
+ constructor(session, signal, childAgent, res = null) {
25
33
  this.session = session;
26
34
  this.signal = signal;
27
35
  this.childAgent = childAgent;
36
+ this.res = res;
28
37
  }
29
38
  toSummaryMessage(summary, createdAt, modelName) {
30
39
  return {
@@ -184,6 +193,10 @@ ${conversation}
184
193
  * 生成对话摘要(支持分层摘要)
185
194
  */
186
195
  async generateSummaryAsync(messages, lastSummary) {
196
+ // 非 childAgent 会话通知 Desktop 显示"上下文压缩中"
197
+ if (!this.childAgent) {
198
+ sendSSE(this.res, { type: 'context_compressing' });
199
+ }
187
200
  const MAX_INPUT_CHARS = 30000; // 单次摘要最大输入字符数
188
201
  // 格式化所有消息用于估算长度
189
202
  const formattedMessages = messages
@@ -39,6 +39,8 @@ class Session {
39
39
  title;
40
40
  selectModelId;
41
41
  messages;
42
+ messageQueue;
43
+ messageQueueAutoExecute;
42
44
  voiceState;
43
45
  createdAt;
44
46
  updatedAt;
@@ -58,6 +60,8 @@ class Session {
58
60
  this.title = data.title || 'New Chat';
59
61
  this.selectModelId = data.selectModelId;
60
62
  this.messages = [];
63
+ this.messageQueue = data.messageQueue || [];
64
+ this.messageQueueAutoExecute = data.messageQueueAutoExecute ?? true;
61
65
  this.voiceState = data.voiceState || { isRecording: false, isPlaying: false };
62
66
  this.lastMessageSummary = data.lastMessageSummary ?? null;
63
67
  this.lastMessageSummaryAt = data.lastMessageSummaryAt ?? null;
@@ -390,7 +394,9 @@ class Session {
390
394
  lastMessageSummary: this.lastMessageSummary,
391
395
  lastMessageSummaryAt: this.lastMessageSummaryAt,
392
396
  unreadCount: this.unreadCount,
393
- isCurrent: this.isCurrent
397
+ isCurrent: this.isCurrent,
398
+ messageQueue: this.messageQueue,
399
+ messageQueueAutoExecute: this.messageQueueAutoExecute
394
400
  };
395
401
  }
396
402
  getStreamDelay(streamSpeed) {
@@ -428,7 +434,7 @@ class Session {
428
434
  const settings = await dataService_js_1.settingsService.get(token);
429
435
  const streamDelay = this.getStreamDelay(settings.streamSpeed);
430
436
  this.currentMessageId = assistantMessageId;
431
- const memoryManager = new MemoryManager_js_1.MemoryManager(this, this.abortController.signal, childAgent);
437
+ const memoryManager = new MemoryManager_js_1.MemoryManager(this, this.abortController.signal, childAgent, res);
432
438
  const historyMessages = await memoryManager.getHistoryMessagesAsync();
433
439
  // SSE 辅助方法:res 为 null 时跳过写入(本地执行模式)
434
440
  const sendSSE = (res, data) => {
@@ -63,7 +63,9 @@ class SessionManager {
63
63
  updatedAt: data.updatedAt,
64
64
  isCurrent: data.isCurrent,
65
65
  lastMessageSummary: data.lastMessageSummary,
66
- lastMessageSummaryAt: data.lastMessageSummaryAt
66
+ lastMessageSummaryAt: data.lastMessageSummaryAt,
67
+ messageQueue: data.messageQueue,
68
+ messageQueueAutoExecute: data.messageQueueAutoExecute
67
69
  });
68
70
  session.loadMessages();
69
71
  return session;
@@ -171,6 +173,10 @@ class SessionManager {
171
173
  session.agentId = updates.agentId;
172
174
  if (updates.unreadCount !== undefined)
173
175
  session.unreadCount = updates.unreadCount;
176
+ if (updates.messageQueue !== undefined)
177
+ session.messageQueue = updates.messageQueue;
178
+ if (updates.messageQueueAutoExecute !== undefined)
179
+ session.messageQueueAutoExecute = updates.messageQueueAutoExecute;
174
180
  session.updatedAt = Date.now();
175
181
  session.save();
176
182
  return session;
@@ -82,17 +82,17 @@ class SessionStore {
82
82
  // ========== Session Operations ==========
83
83
  insertSession(session) {
84
84
  this.db.prepare(`
85
- INSERT INTO sessions (id, user_id, agent_id, title, select_model_id, voice_state, created_at, updated_at,last_message_summary,last_message_summary_at,unread_count,is_current)
86
- VALUES (?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?)
87
- `).run(session.id, session.userId, session.agentId || null, session.title, session.selectModelId || '', JSON.stringify(session.voiceState), session.createdAt, session.updatedAt, session.lastMessageSummary, session.lastMessageSummaryAt, session.unreadCount || 0, session.isCurrent ? 1 : 0);
85
+ INSERT INTO sessions (id, user_id, agent_id, title, select_model_id, voice_state, created_at, updated_at,last_message_summary,last_message_summary_at,unread_count,is_current,message_queue,message_queue_auto_execute)
86
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?,?,?)
87
+ `).run(session.id, session.userId, session.agentId || null, session.title, session.selectModelId || '', JSON.stringify(session.voiceState), session.createdAt, session.updatedAt, session.lastMessageSummary, session.lastMessageSummaryAt, session.unreadCount || 0, session.isCurrent ? 1 : 0, JSON.stringify(session.messageQueue || []), session.messageQueueAutoExecute === false ? 0 : 1);
88
88
  }
89
89
  updateSession(session) {
90
90
  this.db.prepare(`
91
91
  UPDATE sessions
92
92
  SET user_id = ?, agent_id = ?, title = ?, select_model_id = ?,
93
- voice_state = ?, updated_at = ?,last_message_summary=?,last_message_summary_at=?,unread_count=?,is_current=?
93
+ voice_state = ?, updated_at = ?,last_message_summary=?,last_message_summary_at=?,unread_count=?,is_current=?,message_queue=?,message_queue_auto_execute=?
94
94
  WHERE id = ?
95
- `).run(session.userId, session.agentId || null, session.title, session.selectModelId || '', JSON.stringify(session.voiceState), session.updatedAt, session.lastMessageSummary, session.lastMessageSummaryAt, session.unreadCount || 0, session.isCurrent ? 1 : 0, session.id);
95
+ `).run(session.userId, session.agentId || null, session.title, session.selectModelId || '', JSON.stringify(session.voiceState), session.updatedAt, session.lastMessageSummary, session.lastMessageSummaryAt, session.unreadCount || 0, session.isCurrent ? 1 : 0, JSON.stringify(session.messageQueue || []), session.messageQueueAutoExecute === false ? 0 : 1, session.id);
96
96
  }
97
97
  // 支持部分更新的 updateSession
98
98
  updateSessionPartial(id, data) {
@@ -106,6 +106,14 @@ class SessionStore {
106
106
  updates.push('select_model_id = ?');
107
107
  values.push(data.selectModelId || '');
108
108
  }
109
+ if (data.messageQueue !== undefined) {
110
+ updates.push('message_queue = ?');
111
+ values.push(JSON.stringify(data.messageQueue || []));
112
+ }
113
+ if (data.messageQueueAutoExecute !== undefined) {
114
+ updates.push('message_queue_auto_execute = ?');
115
+ values.push(data.messageQueueAutoExecute ? 1 : 0);
116
+ }
109
117
  if (updates.length === 0)
110
118
  return;
111
119
  updates.push('updated_at = ?');
@@ -185,7 +193,9 @@ class SessionStore {
185
193
  lastMessageSummary: row.last_message_summary,
186
194
  lastMessageSummaryAt: row.last_message_summary_at,
187
195
  unreadCount: row.unread_count,
188
- isCurrent: !!row.is_current
196
+ isCurrent: !!row.is_current,
197
+ messageQueueAutoExecute: row.message_queue_auto_execute !== 0,
198
+ messageQueue: JSON.parse(row.message_queue || '[]'),
189
199
  };
190
200
  }
191
201
  /**
@@ -33,10 +33,11 @@ const model_js_1 = require("./model.js");
33
33
  const edit_js_1 = require("./edit.js");
34
34
  const webFetch_js_1 = require("./webFetch.js");
35
35
  const sessionsSpawn_js_1 = require("./sessionsSpawn.js");
36
+ const setSessionTitle_js_1 = require("./setSessionTitle.js");
36
37
  exports.tools = [
37
38
  search_js_1.searchTool, calculator_js_1.calculatorTool, screenshot_js_1.screenshotTool, keyboard_js_1.keyboardTool, mouse_js_1.mouseTool,
38
39
  skill_js_1.skillTool, exec_js_1.execTool, task_js_1.taskTool, model_js_1.modelTool, fetch_js_1.fetchTool,
39
- edit_js_1.editTool, webFetch_js_1.webFetchTool, file_js_1.fileTool, sessionsSpawn_js_1.sessionsSpawnTool
40
+ edit_js_1.editTool, webFetch_js_1.webFetchTool, file_js_1.fileTool, sessionsSpawn_js_1.sessionsSpawnTool, setSessionTitle_js_1.setSessionTitleTool
40
41
  ];
41
42
  function getToolByName(name) {
42
43
  return exports.tools.find(tool => tool.name === name);
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setSessionTitleTool = void 0;
4
+ const AgentManager_js_1 = require("../agent/AgentManager.js");
5
+ const WebSocketService_js_1 = require("../WebSocketService.js");
6
+ exports.setSessionTitleTool = {
7
+ name: 'setSessionTitle',
8
+ description: '修改当前会话的标题。调用此工具后,Desktop 端侧边栏的会话名称会立即更新为新标题。',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ title: {
13
+ type: 'string',
14
+ description: '新的会话标题,建议简洁准确,长度不超过 50 字符',
15
+ },
16
+ },
17
+ required: ['title'],
18
+ },
19
+ handler: async (args, sessionId, _messageId, userId) => {
20
+ try {
21
+ const { title } = args;
22
+ if (!title || typeof title !== 'string' || title.trim().length === 0) {
23
+ return { success: false, errorMessage: '会话标题不能为空' };
24
+ }
25
+ if (!sessionId) {
26
+ return { success: false, errorMessage: '无当前会话,无法修改标题' };
27
+ }
28
+ if (!userId) {
29
+ return { success: false, errorMessage: '未登录' };
30
+ }
31
+ const manager = AgentManager_js_1.agentManagerMap.get(String(userId));
32
+ if (!manager) {
33
+ return { success: false, errorMessage: '无法获取会话管理器' };
34
+ }
35
+ // 找到该 session 所属的 agent
36
+ let targetAgent = null;
37
+ for (const agentInfo of manager.getAgentList()) {
38
+ const agent = manager.getAgent(agentInfo.id);
39
+ const found = agent?.getSessions().find(s => s.id === sessionId);
40
+ if (found) {
41
+ targetAgent = agent;
42
+ break;
43
+ }
44
+ }
45
+ if (!targetAgent) {
46
+ return { success: false, errorMessage: '会话不存在' };
47
+ }
48
+ const updated = targetAgent.updateSession(sessionId, { title: title.trim() });
49
+ if (!updated) {
50
+ return { success: false, errorMessage: '更新会话标题失败' };
51
+ }
52
+ // 推送 session_updated 到 Desktop,触发 UI 刷新
53
+ WebSocketService_js_1.webSocketService.sendToUser(String(userId), {
54
+ type: 'session_updated',
55
+ payload: {
56
+ sessionId,
57
+ agentId: targetAgent.id,
58
+ title: title.trim(),
59
+ updatedAt: updated.updatedAt,
60
+ },
61
+ });
62
+ return {
63
+ success: true,
64
+ output: JSON.stringify({
65
+ sessionId,
66
+ title: title.trim(),
67
+ updatedAt: updated.updatedAt,
68
+ }),
69
+ };
70
+ }
71
+ catch (error) {
72
+ return { success: false, errorMessage: `修改会话标题失败: ${error?.message}` };
73
+ }
74
+ },
75
+ };
@@ -0,0 +1 @@
1
+ ALTER TABLE sessions ADD COLUMN message_queue_auto_execute INTEGER DEFAULT 1;
@@ -0,0 +1 @@
1
+ ALTER TABLE sessions ADD COLUMN message_queue TEXT DEFAULT '[]';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myassis/gateway",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {