@hexabot-ai/api 3.2.2-alpha.3 → 3.2.2-alpha.4
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/extensions/actions/ai/mcp.binding.js +1 -1
- package/dist/extensions/actions/ai/mcp.binding.js.map +1 -1
- package/dist/extensions/channels/web/base-web-channel.d.ts +1 -0
- package/dist/extensions/channels/web/base-web-channel.js +25 -7
- package/dist/extensions/channels/web/base-web-channel.js.map +1 -1
- package/dist/extensions/channels/web/services/web-session.service.d.ts +6 -0
- package/dist/extensions/channels/web/services/web-session.service.js +15 -0
- package/dist/extensions/channels/web/services/web-session.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/extensions/actions/ai/mcp.binding.ts +1 -1
- package/src/extensions/channels/web/base-web-channel.ts +44 -7
- package/src/extensions/channels/web/services/web-session.service.ts +35 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexabot-ai/api",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "3.2.2-alpha.
|
|
4
|
+
"version": "3.2.2-alpha.4",
|
|
5
5
|
"description": "Hexabot is a solution for creating and managing chatbots across multiple channels, leveraging AI for advanced conversational capabilities. It provides a user-friendly interface for building, training, and deploying chatbots with integrated support for various messaging platforms.",
|
|
6
6
|
"author": "Hexastack",
|
|
7
7
|
"license": "FCL-1.0-ALv2",
|
|
@@ -90,8 +90,8 @@
|
|
|
90
90
|
"typeorm": "^0.3.28",
|
|
91
91
|
"yaml": "^2.8.3",
|
|
92
92
|
"zod": "^4.3.6",
|
|
93
|
-
"@hexabot-ai/
|
|
94
|
-
"@hexabot-ai/
|
|
93
|
+
"@hexabot-ai/types": "3.0.2-alpha.4",
|
|
94
|
+
"@hexabot-ai/agentic": "3.1.2-alpha.4"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@compodoc/compodoc": "^1.1.31",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"tsconfig-paths": "^4.2.0",
|
|
143
143
|
"tsconfig-paths-jest": "^0.0.1",
|
|
144
144
|
"typescript": "^5.1.3",
|
|
145
|
-
"@hexabot-ai/frontend": "3.2.2-alpha.
|
|
145
|
+
"@hexabot-ai/frontend": "3.2.2-alpha.4"
|
|
146
146
|
},
|
|
147
147
|
"optionalDependencies": {
|
|
148
148
|
"@css-inline/css-inline-linux-arm64-musl": "^0.14.1",
|
|
@@ -30,7 +30,7 @@ export const aiMcpToolBindingSchema = z.strictObject({
|
|
|
30
30
|
'Optional allow-list of MCP tool names. Leave empty to expose all server tools.',
|
|
31
31
|
'ui:widget': 'AutoCompleteWidget',
|
|
32
32
|
'ui:options': {
|
|
33
|
-
entity: '
|
|
33
|
+
entity: 'McpServer',
|
|
34
34
|
valueKey: 'name',
|
|
35
35
|
labelKey: 'name',
|
|
36
36
|
idFormPath: 'server_id',
|
|
@@ -74,6 +74,10 @@ import { WebSessionService } from './services/web-session.service';
|
|
|
74
74
|
import { WEB_CHANNEL_NAME } from './settings.schema';
|
|
75
75
|
import { Web } from './types';
|
|
76
76
|
|
|
77
|
+
type WebSocketData = Socket['data'] & {
|
|
78
|
+
webMessageQueue?: Promise<void>;
|
|
79
|
+
};
|
|
80
|
+
|
|
77
81
|
/**
|
|
78
82
|
* Base handler for the Socket.IO-backed "web" channel.
|
|
79
83
|
*
|
|
@@ -161,6 +165,30 @@ export default abstract class BaseWebChannelHandler<N extends ChannelName>
|
|
|
161
165
|
return normalizedSourceId.length > 0 ? normalizedSourceId : null;
|
|
162
166
|
}
|
|
163
167
|
|
|
168
|
+
private enqueueMessageDispatch(
|
|
169
|
+
req: SocketRequest,
|
|
170
|
+
event: MessageInboundEvent,
|
|
171
|
+
): void {
|
|
172
|
+
const socket = req.socket as Socket & { data?: WebSocketData };
|
|
173
|
+
const socketData = (socket.data ??= {});
|
|
174
|
+
// Keep chatbot processing ordered per socket without making the client ack
|
|
175
|
+
// wait for slow actions, LLM calls, or external integrations.
|
|
176
|
+
const previous = socketData.webMessageQueue ?? Promise.resolve();
|
|
177
|
+
const next = previous
|
|
178
|
+
.catch(() => undefined)
|
|
179
|
+
.then(() => this.channelEventBus.emitMessage(event))
|
|
180
|
+
.catch((err) => {
|
|
181
|
+
this.logger.error('Failed to process web socket message', err);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
socketData.webMessageQueue = next;
|
|
185
|
+
void next.finally(() => {
|
|
186
|
+
if (socketData.webMessageQueue === next) {
|
|
187
|
+
delete socketData.webMessageQueue;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
164
192
|
@OnEvent('hook:websocket:connection', { async: true })
|
|
165
193
|
async onWebSocketConnection(client: Socket) {
|
|
166
194
|
try {
|
|
@@ -547,15 +575,24 @@ export default abstract class BaseWebChannelHandler<N extends ChannelName>
|
|
|
547
575
|
messageEvent.setAuthorForeignId(profile.foreignId);
|
|
548
576
|
}
|
|
549
577
|
messageEvent.setCreatedAt(new Date());
|
|
578
|
+
// Resolve the thread before acknowledging the socket request so the
|
|
579
|
+
// client receives a stable thread_id, then dispatch chatbot work later.
|
|
580
|
+
const thread = await this.sessionService.resolveThreadForIncoming(
|
|
581
|
+
req,
|
|
582
|
+
profile.id,
|
|
583
|
+
{
|
|
584
|
+
explicitThreadId: messageEvent.getThreadId(),
|
|
585
|
+
inactivityHours: this.sessionService.resolveInactivityHours(
|
|
586
|
+
source.settings,
|
|
587
|
+
),
|
|
588
|
+
sourceId: source.id,
|
|
589
|
+
},
|
|
590
|
+
);
|
|
591
|
+
messageEvent.setThreadId(thread.id);
|
|
592
|
+
messageEvent.setThreadIdOnRaw(thread.id);
|
|
550
593
|
|
|
551
594
|
this.broadcast(profile, StdEventType.message, messageEvent.getRaw());
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const resolvedThreadId = messageEvent.getThreadId();
|
|
555
|
-
if (resolvedThreadId) {
|
|
556
|
-
messageEvent.setThreadIdOnRaw(resolvedThreadId);
|
|
557
|
-
if (req.session.web) req.session.web.threadId = resolvedThreadId;
|
|
558
|
-
}
|
|
595
|
+
this.enqueueMessageDispatch(req, messageEvent);
|
|
559
596
|
|
|
560
597
|
continue;
|
|
561
598
|
}
|
|
@@ -215,6 +215,10 @@ export class WebSessionService {
|
|
|
215
215
|
return this.threadService.resolveThread({ subscriberId, explicitThreadId });
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
resolveInactivityHours(settings: unknown): number {
|
|
219
|
+
return this.threadService.resolveInactivityHours(settings);
|
|
220
|
+
}
|
|
221
|
+
|
|
218
222
|
/**
|
|
219
223
|
* Resolves a thread from the request query/body and writes the result back
|
|
220
224
|
* to the session. Used by the subscribe/history flows.
|
|
@@ -232,4 +236,35 @@ export class WebSessionService {
|
|
|
232
236
|
|
|
233
237
|
return thread;
|
|
234
238
|
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Resolves the writable thread for an incoming message and persists it on the
|
|
242
|
+
* socket session before chatbot processing continues asynchronously.
|
|
243
|
+
*/
|
|
244
|
+
async resolveThreadForIncoming(
|
|
245
|
+
req: SocketRequest,
|
|
246
|
+
subscriberId: string,
|
|
247
|
+
{
|
|
248
|
+
explicitThreadId,
|
|
249
|
+
inactivityHours,
|
|
250
|
+
sourceId,
|
|
251
|
+
}: {
|
|
252
|
+
explicitThreadId?: string;
|
|
253
|
+
inactivityHours?: number;
|
|
254
|
+
sourceId?: string;
|
|
255
|
+
},
|
|
256
|
+
): Promise<Thread> {
|
|
257
|
+
const thread = await this.threadService.resolveThreadForIncoming({
|
|
258
|
+
subscriberId,
|
|
259
|
+
explicitThreadId,
|
|
260
|
+
inactivityHours,
|
|
261
|
+
sourceId,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (req.session.web) {
|
|
265
|
+
req.session.web.threadId = thread.id;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return thread;
|
|
269
|
+
}
|
|
235
270
|
}
|