@myassis/gateway 1.0.29 → 1.0.31

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
  /**
@@ -1,9 +1,20 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.getGlobalModelSelector = exports.parseAruments = exports.LLMClient = void 0;
4
7
  const index_js_1 = require("../../stores/index.js");
5
8
  const shared_1 = require("@myassis/shared");
9
+ const promises_1 = __importDefault(require("fs/promises"));
6
10
  const logger = (0, shared_1.getLogger)('LLMClient');
11
+ function convertBase64ToImage(base64Img) {
12
+ // 去掉data:image/xxx;base64,前缀
13
+ const pureBase64 = base64Img.replace(/^data:image\/\w+;base64,/, '');
14
+ const buf = Buffer.from(pureBase64, 'base64');
15
+ // 写入文件
16
+ promises_1.default.writeFile('screenshot.png', buf);
17
+ }
7
18
  /**
8
19
  * LLM 调用器类
9
20
  * 提供 Chat 和 streamChat 两种调用方式
@@ -126,293 +137,189 @@ class LLMClient {
126
137
  if (!apiKey) {
127
138
  throw new Error('No API Key');
128
139
  }
129
- if (model.baseUrl.includes('coze.com')) {
130
- // Coze API: 使用 query 字段,只支持文本
131
- const lastMessage = this.messages[this.messages.length - 1];
132
- let queryContent = lastMessage?.content || '';
133
- // 如果有附件,在查询中添加附件信息
134
- if (lastMessage?.attachments && lastMessage.attachments.length > 0) {
135
- const attachmentInfos = lastMessage.attachments.map(a => `[${a.type === 'image' ? '图片' : '文件'}: ${a.name}](${a.url})`).join('\n');
136
- queryContent += `\n\n${attachmentInfos}`;
137
- }
138
- return {
139
- url: `${model.baseUrl}/chat`,
140
- headers: {
141
- 'Content-Type': 'application/json',
142
- 'Authorization': `Bearer ${apiKey}`,
143
- },
144
- body: {
145
- bot_id: model.modelId,
146
- conversation_id: '', // 非会话模式
147
- user: '',
148
- query: queryContent,
149
- stream,
150
- },
151
- };
152
- }
153
- else if (model.baseUrl.includes('anthropic.com')) {
154
- return {
155
- url: `${model.baseUrl}/v1/messages`,
156
- headers: {
157
- 'Content-Type': 'application/json',
158
- 'x-api-key': apiKey || '',
159
- 'anthropic-version': '2023-06-01',
160
- 'anthropic-dangerous-direct-browser-access': 'true',
161
- },
162
- body: {
163
- model: model.modelId,
164
- messages: this.messages.filter((m) => m.role !== 'system').map((m) => {
165
- // 处理工具消息
166
- if (m.role === 'tool') {
167
- return {
168
- role: 'user',
169
- content: [
170
- {
171
- type: 'tool_result',
172
- tool_use_id: m.tool_call_id,
173
- content: m.content,
174
- }
175
- ],
176
- };
140
+ // OpenAI compatible API
141
+ let existAttachments = false;
142
+ let existScreenShot = false;
143
+ const body = {
144
+ model: model.modelId,
145
+ messages: this.messages.map((m, index) => {
146
+ if (m.role === 'tool') {
147
+ if (m.tool_call_name == 'screenshot') {
148
+ if (index === this.messages.length - 1) {
149
+ existScreenShot = true;
150
+ const contentObj = JSON.parse(m.content);
151
+ return [{
152
+ role: 'tool',
153
+ tool_call_id: m.tool_call_id,
154
+ content: JSON.stringify({
155
+ success: contentObj.success,
156
+ result_type: 'image',
157
+ image_url: contentObj.output,
158
+ text_for_llm: '工具生成了一张图片,图片地址已返回。'
159
+ }),
160
+ }];
177
161
  }
178
- // 处理用户消息中的附件
179
- if (m.role === 'user' && m.attachments && m.attachments.length > 0) {
180
- const contentArray = [];
181
- // 如果有文本内容,先添加文本
182
- if (m.content && m.content.trim()) {
183
- contentArray.push({
184
- type: 'text',
185
- text: m.content,
186
- });
187
- }
188
- // 添加附件
189
- for (const attachment of m.attachments) {
190
- if (attachment.type === 'image') {
191
- // Anthropic 支持 base64 图片
192
- // 假设 attachment.url 可能是 base64 格式或 URL 格式
193
- if (attachment.url.startsWith('data:')) {
194
- // base64 格式
195
- const base64Data = attachment.url.split(',')[1];
196
- const mimeType = attachment.mimeType || 'image/png';
197
- contentArray.push({
198
- type: 'image',
199
- source: {
200
- type: 'base64',
201
- media_type: mimeType,
202
- data: base64Data,
203
- },
204
- });
205
- }
206
- else {
207
- // URL 格式 - Anthropic 也支持
208
- contentArray.push({
209
- type: 'image',
210
- source: {
211
- type: 'url',
212
- media_type: attachment.mimeType || 'image/png',
213
- url: attachment.url,
214
- },
215
- });
216
- }
217
- }
218
- else {
219
- // 其他文件类型 - Anthropic 不直接支持,添加为文本引用
220
- const fileInfo = `[附件: ${attachment.name}](${attachment.url})`;
221
- if (contentArray.length === 0) {
222
- contentArray.push({
223
- type: 'text',
224
- text: fileInfo,
225
- });
226
- }
227
- else {
228
- const lastItem = contentArray[contentArray.length - 1];
229
- if (lastItem.type === 'text') {
230
- lastItem.text += `\n${fileInfo}`;
231
- }
232
- else {
233
- contentArray.push({
234
- type: 'text',
235
- text: fileInfo,
236
- });
237
- }
238
- }
239
- }
240
- }
241
- return {
242
- role: 'user',
243
- content: contentArray,
244
- };
162
+ else {
163
+ return [{
164
+ role: 'tool',
165
+ tool_call_id: m.tool_call_id,
166
+ content: m.content.substring(0, 100) + '...(内容过长已截断)',
167
+ }];
245
168
  }
246
- // 普通用户消息(无附件)
247
- return {
248
- role: m.role,
249
- content: m.content,
250
- };
251
- }),
252
- stream,
253
- max_tokens: model.maxTokens || 4096,
254
- },
255
- };
256
- }
257
- else {
258
- // OpenAI compatible API
259
- let existAttachments = false;
260
- const body = {
261
- model: model.modelId,
262
- messages: this.messages.map((m) => {
263
- if (m.role === 'tool') {
169
+ }
170
+ else {
264
171
  return [{
265
172
  role: 'tool',
266
173
  tool_call_id: m.tool_call_id,
267
174
  content: m.content,
268
175
  }];
269
176
  }
270
- // 助手调用工具的消息:必须保留 tool_calls!!(你之前丢了,导致报错)
271
- if (m.role === 'assistant' && m.tool_calls) {
272
- return [{
273
- role: 'assistant',
274
- content: m.content || null,
275
- tool_calls: m.tool_calls.map(m => {
276
- return {
277
- id: m.id,
278
- function: {
279
- name: m.toolName,
280
- arguments: m.input
281
- },
282
- type: 'function'
283
- };
284
- }),
285
- }];
286
- }
287
- if (m.role === 'assistant' && m.toolCalls) {
288
- let items = [];
289
- for (let toolCall of m.toolCalls) {
290
- const item = {
291
- role: 'assistant',
292
- content: toolCall.content,
293
- reasoning_content: toolCall.reasoningContent,
294
- tool_calls: []
295
- };
296
- const tools = [];
297
- for (let i = 0; i < toolCall.toolCalls.length; i++) {
298
- const toolCallItem = toolCall.toolCalls[i];
299
- if (toolCallItem.output != null) {
300
- item.tool_calls.push({
301
- id: toolCallItem.id,
302
- function: {
303
- name: toolCallItem.toolName,
304
- arguments: toolCallItem.input
305
- },
306
- type: 'function'
307
- });
308
- tools.push({
309
- role: 'tool',
310
- tool_call_id: toolCallItem.id,
311
- content: toolCallItem.output.substring(0, 100) + '...' + '(内容过长已截断)'
312
- });
313
- }
314
- }
315
- if (item.tool_calls.length > 0) {
316
- items.push(item);
317
- items = items.concat(tools);
177
+ }
178
+ // 助手调用工具的消息:必须保留 tool_calls!!(你之前丢了,导致报错)
179
+ if (m.role === 'assistant' && m.tool_calls) {
180
+ return [{
181
+ role: 'assistant',
182
+ content: m.content || null,
183
+ tool_calls: m.tool_calls.map(m => {
184
+ return {
185
+ id: m.id,
186
+ function: {
187
+ name: m.toolName,
188
+ arguments: m.input
189
+ },
190
+ type: 'function'
191
+ };
192
+ }),
193
+ }];
194
+ }
195
+ if (m.role === 'assistant' && m.toolCalls) {
196
+ let items = [];
197
+ for (let toolCall of m.toolCalls) {
198
+ const item = {
199
+ role: 'assistant',
200
+ content: toolCall.content,
201
+ reasoning_content: toolCall.reasoningContent,
202
+ tool_calls: []
203
+ };
204
+ const tools = [];
205
+ for (let i = 0; i < toolCall.toolCalls.length; i++) {
206
+ const toolCallItem = toolCall.toolCalls[i];
207
+ if (toolCallItem.output != null) {
208
+ item.tool_calls.push({
209
+ id: toolCallItem.id,
210
+ function: {
211
+ name: toolCallItem.toolName,
212
+ arguments: toolCallItem.input
213
+ },
214
+ type: 'function'
215
+ });
216
+ tools.push({
217
+ role: 'tool',
218
+ tool_call_id: toolCallItem.id,
219
+ content: toolCallItem.output.substring(0, 100) + '...' + '(内容过长已截断)'
220
+ });
318
221
  }
319
222
  }
320
- if (m.content) {
321
- items.push({
322
- role: 'assistant',
323
- content: m.content
324
- });
223
+ if (item.tool_calls.length > 0) {
224
+ items.push(item);
225
+ items = items.concat(tools);
325
226
  }
326
- return items;
327
227
  }
328
- // 处理用户消息中的附件
329
- if (m.role === 'user' && m.attachments && m.attachments.length > 0) {
330
- existAttachments = true;
331
- const contentArray = [];
332
- // 添加附件
333
- for (const attachment of m.attachments) {
334
- if (attachment.type === 'image') {
335
- // 图片附件
336
- contentArray.push({
337
- type: 'image_url',
338
- image_url: {
339
- url: attachment.url,
340
- detail: 'high',
341
- },
342
- });
343
- }
344
- else if (attachment.type === 'audio') {
345
- // 音频附件 - 使用 file 类型
228
+ if (m.content) {
229
+ items.push({
230
+ role: 'assistant',
231
+ content: m.content
232
+ });
233
+ }
234
+ return items;
235
+ }
236
+ // 处理用户消息中的附件
237
+ if (m.role === 'user' && m.attachments && m.attachments.length > 0) {
238
+ existAttachments = true;
239
+ const contentArray = [];
240
+ // 添加附件
241
+ for (const attachment of m.attachments) {
242
+ if (attachment.type === 'image') {
243
+ // 图片附件
244
+ contentArray.push({
245
+ type: 'image_url',
246
+ image_url: {
247
+ url: attachment.url,
248
+ detail: 'high',
249
+ },
250
+ });
251
+ }
252
+ else if (attachment.type === 'audio') {
253
+ // 音频附件 - 使用 file 类型
254
+ contentArray.push({
255
+ type: 'input_audio',
256
+ input_audio: {
257
+ data: attachment.url, // 如果是 base64 格式
258
+ format: attachment.mimeType?.split('/')[1] || 'wav',
259
+ },
260
+ });
261
+ }
262
+ else {
263
+ // 其他文件类型:video, file - 添加为文本引用
264
+ const fileInfo = `[附件: ${attachment.name}](${attachment.url})`;
265
+ if (contentArray.length === 0) {
346
266
  contentArray.push({
347
- type: 'input_audio',
348
- input_audio: {
349
- data: attachment.url, // 如果是 base64 格式
350
- format: attachment.mimeType?.split('/')[1] || 'wav',
351
- },
267
+ type: 'text',
268
+ text: fileInfo,
352
269
  });
353
270
  }
354
271
  else {
355
- // 其他文件类型:video, file - 添加为文本引用
356
- const fileInfo = `[附件: ${attachment.name}](${attachment.url})`;
357
- if (contentArray.length === 0) {
272
+ // 如果已经有文本,将文件信息追加到文本中
273
+ const lastItem = contentArray[contentArray.length - 1];
274
+ if (lastItem.type === 'text') {
275
+ lastItem.text += `\n${fileInfo}`;
276
+ }
277
+ else {
358
278
  contentArray.push({
359
279
  type: 'text',
360
280
  text: fileInfo,
361
281
  });
362
282
  }
363
- else {
364
- // 如果已经有文本,将文件信息追加到文本中
365
- const lastItem = contentArray[contentArray.length - 1];
366
- if (lastItem.type === 'text') {
367
- lastItem.text += `\n${fileInfo}`;
368
- }
369
- else {
370
- contentArray.push({
371
- type: 'text',
372
- text: fileInfo,
373
- });
374
- }
375
- }
376
283
  }
377
284
  }
378
- // 如果有文本内容,添加文本
379
- if (m.content && m.content.trim()) {
380
- contentArray.push({
381
- type: 'text',
382
- text: m.content,
383
- });
384
- }
385
- return [{
386
- role: m.role,
387
- content: contentArray,
388
- }];
389
285
  }
390
- // 普通消息(无附件)
286
+ // 如果有文本内容,添加文本
287
+ if (m.content && m.content.trim()) {
288
+ contentArray.push({
289
+ type: 'text',
290
+ text: m.content,
291
+ });
292
+ }
391
293
  return [{
392
294
  role: m.role,
393
- content: m.content,
295
+ content: contentArray,
394
296
  }];
395
- }).flatMap(x => x),
396
- stream,
397
- enable_thinking: true,
398
- };
399
- if (this.tools && this.tools.length > 0) {
400
- body.tools = this.tools;
401
- }
402
- const tokens = JSON.stringify(body).length;
403
- logger.debug('tokens', tokens);
404
- if (tokens > 200000 && !existAttachments) {
405
- throw Error('exceed max message tokens');
406
- }
407
- return {
408
- url: `${model.baseUrl}/chat/completions`,
409
- headers: {
410
- 'Content-Type': 'application/json',
411
- 'Authorization': `Bearer ${apiKey}`,
412
- },
413
- body,
414
- };
297
+ }
298
+ // 普通消息(无附件)
299
+ return [{
300
+ role: m.role,
301
+ content: m.content,
302
+ }];
303
+ }).flatMap(x => x),
304
+ stream,
305
+ enable_thinking: true,
306
+ };
307
+ if (this.tools && this.tools.length > 0) {
308
+ body.tools = this.tools;
415
309
  }
310
+ const tokens = JSON.stringify(body).length;
311
+ logger.debug('tokens', tokens);
312
+ if (tokens > 200000 && !existAttachments && !existScreenShot) {
313
+ throw Error('exceed max message tokens');
314
+ }
315
+ return {
316
+ url: `${model.baseUrl}/chat/completions`,
317
+ headers: {
318
+ 'Content-Type': 'application/json',
319
+ 'Authorization': `Bearer ${apiKey}`,
320
+ },
321
+ body,
322
+ };
416
323
  }
417
324
  /**
418
325
  * 执行流式请求
@@ -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) {
@@ -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
  /**
@@ -15,7 +15,7 @@ exports.screenshotTool = {
15
15
  const base64 = imgBuffer.toString('base64');
16
16
  return {
17
17
  success: true,
18
- output: JSON.stringify({ image: `data:image/jpeg;base64,${base64}`, size: imgBuffer.length }),
18
+ output: `data:image/jpeg;base64,${base64}`,
19
19
  };
20
20
  }
21
21
  catch (error) {
@@ -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.29",
3
+ "version": "1.0.31",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {