@easbot/gateway 0.2.39 → 0.2.41
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/chunks/chunk-3SBZTZXS.cjs +7 -0
- package/dist/chunks/chunk-OBFSXYWV.mjs +30 -0
- package/dist/chunks/chunk-RFOEJ3A2.cjs +30 -0
- package/dist/chunks/chunk-RGPJTZUB.mjs +7 -0
- package/dist/chunks/log-FQII2FT4.mjs +1 -0
- package/dist/chunks/log-VLMXTUPA.cjs +1 -0
- package/dist/chunks/server-3QASQ56E.cjs +1 -0
- package/dist/chunks/server-54GY5XXD.mjs +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +210 -23
- package/dist/index.d.ts +210 -23
- package/dist/index.mjs +2 -2
- package/package.json +5 -5
- package/dist/chunks/chunk-7OFQ65NG.mjs +0 -7
- package/dist/chunks/chunk-AUPHFE34.cjs +0 -7
- package/dist/chunks/chunk-GY3SWWW3.cjs +0 -1
- package/dist/chunks/chunk-H425RRAV.mjs +0 -18
- package/dist/chunks/chunk-HAMGVOQD.mjs +0 -1
- package/dist/chunks/chunk-O6R6U45A.cjs +0 -18
- package/dist/chunks/global-FIBJJFBN.cjs +0 -1
- package/dist/chunks/global-Z3HUTR5L.mjs +0 -2
- package/dist/chunks/log-JFEBRH2W.cjs +0 -1
- package/dist/chunks/log-MIT4H7S5.mjs +0 -1
- package/dist/chunks/server-4GO5DAEQ.cjs +0 -1
- package/dist/chunks/server-QOFBCSK5.mjs +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ declare const ChannelTypeSchema: z.ZodEnum<{
|
|
|
42
42
|
webchat: "webchat";
|
|
43
43
|
signal: "signal";
|
|
44
44
|
nostr: "nostr";
|
|
45
|
+
dingtalk: "dingtalk";
|
|
45
46
|
}>;
|
|
46
47
|
type ChannelType = z.infer<typeof ChannelTypeSchema>;
|
|
47
48
|
declare const MessagePrioritySchema: z.ZodEnum<{
|
|
@@ -193,6 +194,20 @@ declare const ChannelConfigSchema: z.ZodObject<{
|
|
|
193
194
|
maxConnections: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
194
195
|
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
195
196
|
}, z.core.$strip>>;
|
|
197
|
+
dingtalk: z.ZodOptional<z.ZodObject<{
|
|
198
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
199
|
+
appKey: z.ZodString;
|
|
200
|
+
appSecret: z.ZodString;
|
|
201
|
+
token: z.ZodOptional<z.ZodString>;
|
|
202
|
+
encryptKey: z.ZodOptional<z.ZodString>;
|
|
203
|
+
webhook: z.ZodOptional<z.ZodObject<{
|
|
204
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
205
|
+
path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
206
|
+
port: z.ZodOptional<z.ZodNumber>;
|
|
207
|
+
}, z.core.$strip>>;
|
|
208
|
+
maxConnections: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
209
|
+
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
210
|
+
}, z.core.$strip>>;
|
|
196
211
|
}, z.core.$strip>;
|
|
197
212
|
declare const HTTPSConfigSchema: z.ZodObject<{
|
|
198
213
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -549,6 +564,20 @@ declare const GatewayConfigSchema: z.ZodObject<{
|
|
|
549
564
|
maxConnections: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
550
565
|
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
551
566
|
}, z.core.$strip>>;
|
|
567
|
+
dingtalk: z.ZodOptional<z.ZodObject<{
|
|
568
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
569
|
+
appKey: z.ZodString;
|
|
570
|
+
appSecret: z.ZodString;
|
|
571
|
+
token: z.ZodOptional<z.ZodString>;
|
|
572
|
+
encryptKey: z.ZodOptional<z.ZodString>;
|
|
573
|
+
webhook: z.ZodOptional<z.ZodObject<{
|
|
574
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
575
|
+
path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
576
|
+
port: z.ZodOptional<z.ZodNumber>;
|
|
577
|
+
}, z.core.$strip>>;
|
|
578
|
+
maxConnections: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
579
|
+
timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
580
|
+
}, z.core.$strip>>;
|
|
552
581
|
}, z.core.$strip>>;
|
|
553
582
|
cluster: z.ZodOptional<z.ZodObject<{
|
|
554
583
|
nodeId: z.ZodString;
|
|
@@ -705,6 +734,9 @@ interface ChannelCapabilities {
|
|
|
705
734
|
supportsHtml: boolean;
|
|
706
735
|
supportsDeliveryReceipt: boolean;
|
|
707
736
|
supportsReadReceipt: boolean;
|
|
737
|
+
supportsSlashCommands: boolean;
|
|
738
|
+
supportsNativeCommands: boolean;
|
|
739
|
+
commandPrefix: string;
|
|
708
740
|
maxMessageLength: number;
|
|
709
741
|
maxMediaCount: number;
|
|
710
742
|
}
|
|
@@ -1562,6 +1594,12 @@ declare abstract class BaseChannelPlugin implements ChannelPlugin {
|
|
|
1562
1594
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
1563
1595
|
protected handleMessage(message: GatewayMessage): Promise<void>;
|
|
1564
1596
|
protected handleEvent(type: string, data?: unknown): Promise<void>;
|
|
1597
|
+
protected getCommandList(): Promise<Array<{
|
|
1598
|
+
name: string;
|
|
1599
|
+
description?: string;
|
|
1600
|
+
agent?: string;
|
|
1601
|
+
model?: string;
|
|
1602
|
+
}>>;
|
|
1565
1603
|
}
|
|
1566
1604
|
|
|
1567
1605
|
interface PluginLoaderConfig {
|
|
@@ -1634,6 +1672,8 @@ declare class MessageStore {
|
|
|
1634
1672
|
private storagePath;
|
|
1635
1673
|
private dirty;
|
|
1636
1674
|
constructor(config?: Partial<MessageStoreConfig>);
|
|
1675
|
+
loadFromDisk(): Promise<number>;
|
|
1676
|
+
private addToSessionMessages;
|
|
1637
1677
|
private ensureDir;
|
|
1638
1678
|
private getMessageFilePath;
|
|
1639
1679
|
private getSessionDir;
|
|
@@ -1876,6 +1916,7 @@ declare class GatewayServer implements IGatewayServer {
|
|
|
1876
1916
|
private wsServer;
|
|
1877
1917
|
private running;
|
|
1878
1918
|
private connections;
|
|
1919
|
+
private gatewayAgent;
|
|
1879
1920
|
constructor(config: GatewayServerConfig$1);
|
|
1880
1921
|
private loadChannelPlugins;
|
|
1881
1922
|
start(): Promise<void>;
|
|
@@ -1889,11 +1930,10 @@ declare class GatewayServer implements IGatewayServer {
|
|
|
1889
1930
|
onMessage(message: GatewayMessage): Promise<void>;
|
|
1890
1931
|
private saveContactFromMessage;
|
|
1891
1932
|
private dispatchToAgent;
|
|
1933
|
+
private getGatewayAgent;
|
|
1934
|
+
private dispatchToGatewayAgent;
|
|
1892
1935
|
private buildChannelContext;
|
|
1893
|
-
private
|
|
1894
|
-
private executeLocalAgent;
|
|
1895
|
-
private dispatchToLocalAgentWithFallback;
|
|
1896
|
-
private executeLocalAgentWithFallback;
|
|
1936
|
+
private executeGatewayAgent;
|
|
1897
1937
|
private handleAgentResult;
|
|
1898
1938
|
private handleAgentError;
|
|
1899
1939
|
private dispatchToSubAgent;
|
|
@@ -2187,6 +2227,9 @@ declare class TelegramPlugin extends BaseChannelPlugin {
|
|
|
2187
2227
|
supportsHtml: boolean;
|
|
2188
2228
|
supportsDeliveryReceipt: boolean;
|
|
2189
2229
|
supportsReadReceipt: boolean;
|
|
2230
|
+
supportsSlashCommands: boolean;
|
|
2231
|
+
supportsNativeCommands: boolean;
|
|
2232
|
+
commandPrefix: string;
|
|
2190
2233
|
maxMessageLength: number;
|
|
2191
2234
|
maxMediaCount: number;
|
|
2192
2235
|
};
|
|
@@ -2216,6 +2259,7 @@ declare class TelegramPlugin extends BaseChannelPlugin {
|
|
|
2216
2259
|
private getUpdates;
|
|
2217
2260
|
private sendApiMessage;
|
|
2218
2261
|
private request;
|
|
2262
|
+
private syncBotCommands;
|
|
2219
2263
|
}
|
|
2220
2264
|
|
|
2221
2265
|
interface DiscordBotConfig {
|
|
@@ -2223,13 +2267,39 @@ interface DiscordBotConfig {
|
|
|
2223
2267
|
applicationId?: string;
|
|
2224
2268
|
gateway?: {
|
|
2225
2269
|
enabled: boolean;
|
|
2226
|
-
intents
|
|
2270
|
+
intents?: number[];
|
|
2227
2271
|
};
|
|
2228
2272
|
webhook?: {
|
|
2229
2273
|
enabled: boolean;
|
|
2230
2274
|
path: string;
|
|
2231
2275
|
port?: number;
|
|
2232
2276
|
};
|
|
2277
|
+
commands?: DiscordCommand[];
|
|
2278
|
+
retry?: {
|
|
2279
|
+
maxAttempts?: number;
|
|
2280
|
+
initialDelay?: number;
|
|
2281
|
+
maxDelay?: number;
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
interface DiscordCommand {
|
|
2285
|
+
name: string;
|
|
2286
|
+
description: string;
|
|
2287
|
+
options?: Array<{
|
|
2288
|
+
name: string;
|
|
2289
|
+
description: string;
|
|
2290
|
+
type: number;
|
|
2291
|
+
required?: boolean;
|
|
2292
|
+
}>;
|
|
2293
|
+
handler: (ctx: DiscordCommandContext) => Promise<void>;
|
|
2294
|
+
}
|
|
2295
|
+
interface DiscordCommandContext {
|
|
2296
|
+
userId: string;
|
|
2297
|
+
guildId?: string;
|
|
2298
|
+
channelId: string;
|
|
2299
|
+
messageId: string;
|
|
2300
|
+
commandName: string;
|
|
2301
|
+
options: Record<string, unknown>;
|
|
2302
|
+
reply?: (text: string) => Promise<string>;
|
|
2233
2303
|
}
|
|
2234
2304
|
declare class DiscordPlugin extends BaseChannelPlugin {
|
|
2235
2305
|
readonly id: string;
|
|
@@ -2242,12 +2312,20 @@ declare class DiscordPlugin extends BaseChannelPlugin {
|
|
|
2242
2312
|
private sessionId;
|
|
2243
2313
|
private sequenceNumber;
|
|
2244
2314
|
private abortController;
|
|
2315
|
+
private processedMessageIds;
|
|
2316
|
+
private sentMessages;
|
|
2317
|
+
private sessionIdMap;
|
|
2318
|
+
private commandRouter;
|
|
2245
2319
|
private reconnectAttempts;
|
|
2246
2320
|
private maxReconnectAttempts;
|
|
2321
|
+
private retryState;
|
|
2247
2322
|
constructor(id?: string);
|
|
2248
2323
|
protected doStart(): Promise<void>;
|
|
2249
2324
|
protected doStop(): Promise<void>;
|
|
2325
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2250
2326
|
send(message: GatewayMessage): Promise<string>;
|
|
2327
|
+
private createMessage;
|
|
2328
|
+
private syncCommands;
|
|
2251
2329
|
getCapabilities(): {
|
|
2252
2330
|
supportsText: boolean;
|
|
2253
2331
|
supportsMedia: boolean;
|
|
@@ -2261,6 +2339,9 @@ declare class DiscordPlugin extends BaseChannelPlugin {
|
|
|
2261
2339
|
supportsHtml: boolean;
|
|
2262
2340
|
supportsDeliveryReceipt: boolean;
|
|
2263
2341
|
supportsReadReceipt: boolean;
|
|
2342
|
+
supportsSlashCommands: boolean;
|
|
2343
|
+
supportsNativeCommands: boolean;
|
|
2344
|
+
commandPrefix: string;
|
|
2264
2345
|
maxMessageLength: number;
|
|
2265
2346
|
maxMediaCount: number;
|
|
2266
2347
|
};
|
|
@@ -2268,14 +2349,17 @@ declare class DiscordPlugin extends BaseChannelPlugin {
|
|
|
2268
2349
|
private handleGatewayMessage;
|
|
2269
2350
|
private handleHello;
|
|
2270
2351
|
private handleDispatch;
|
|
2352
|
+
private handleReactionEvent;
|
|
2353
|
+
private findSentMessageEntry;
|
|
2271
2354
|
private handleDiscordMessage;
|
|
2272
2355
|
private toGatewayMessage;
|
|
2273
2356
|
private parseContent;
|
|
2357
|
+
private downloadFile;
|
|
2358
|
+
private downloadTextFile;
|
|
2274
2359
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2275
2360
|
private processMessageAndGetSessionId;
|
|
2276
2361
|
private getCurrentUser;
|
|
2277
2362
|
private getGatewayBot;
|
|
2278
|
-
private createMessage;
|
|
2279
2363
|
private request;
|
|
2280
2364
|
}
|
|
2281
2365
|
|
|
@@ -2289,6 +2373,24 @@ interface SlackBotConfig {
|
|
|
2289
2373
|
path: string;
|
|
2290
2374
|
port?: number;
|
|
2291
2375
|
};
|
|
2376
|
+
commands?: SlackBotCommand[];
|
|
2377
|
+
retry?: {
|
|
2378
|
+
maxAttempts?: number;
|
|
2379
|
+
initialDelay?: number;
|
|
2380
|
+
maxDelay?: number;
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
interface SlackBotCommand {
|
|
2384
|
+
command: string;
|
|
2385
|
+
description: string;
|
|
2386
|
+
handler: (ctx: SlackCommandContext) => Promise<void>;
|
|
2387
|
+
}
|
|
2388
|
+
interface SlackCommandContext {
|
|
2389
|
+
channelId: string;
|
|
2390
|
+
userId: string;
|
|
2391
|
+
args: string[];
|
|
2392
|
+
ts: string;
|
|
2393
|
+
reply?: (text: string) => Promise<string>;
|
|
2292
2394
|
}
|
|
2293
2395
|
declare class SlackPlugin extends BaseChannelPlugin {
|
|
2294
2396
|
readonly id: string;
|
|
@@ -2298,10 +2400,22 @@ declare class SlackPlugin extends BaseChannelPlugin {
|
|
|
2298
2400
|
private baseUrl;
|
|
2299
2401
|
private socketModeClient;
|
|
2300
2402
|
private abortController;
|
|
2403
|
+
private processedMessageIds;
|
|
2404
|
+
private sentMessages;
|
|
2405
|
+
private sessionIdMap;
|
|
2406
|
+
private commandRouter;
|
|
2407
|
+
private retryState;
|
|
2408
|
+
private socketReconnectAttempts;
|
|
2409
|
+
private maxSocketReconnectAttempts;
|
|
2301
2410
|
constructor(id?: string);
|
|
2302
2411
|
protected doStart(): Promise<void>;
|
|
2303
2412
|
protected doStop(): Promise<void>;
|
|
2413
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2304
2414
|
send(message: GatewayMessage): Promise<string>;
|
|
2415
|
+
private postMessage;
|
|
2416
|
+
private postImage;
|
|
2417
|
+
private postFile;
|
|
2418
|
+
private uploadFile;
|
|
2305
2419
|
getCapabilities(): {
|
|
2306
2420
|
supportsText: boolean;
|
|
2307
2421
|
supportsMedia: boolean;
|
|
@@ -2315,18 +2429,31 @@ declare class SlackPlugin extends BaseChannelPlugin {
|
|
|
2315
2429
|
supportsHtml: boolean;
|
|
2316
2430
|
supportsDeliveryReceipt: boolean;
|
|
2317
2431
|
supportsReadReceipt: boolean;
|
|
2432
|
+
supportsSlashCommands: boolean;
|
|
2433
|
+
supportsNativeCommands: boolean;
|
|
2434
|
+
commandPrefix: string;
|
|
2318
2435
|
maxMessageLength: number;
|
|
2319
2436
|
maxMediaCount: number;
|
|
2320
2437
|
};
|
|
2321
2438
|
private startSocketMode;
|
|
2322
2439
|
private handleSocketModeEvent;
|
|
2440
|
+
private handleReactionEvent;
|
|
2441
|
+
private findSentMessageEntry;
|
|
2323
2442
|
private handleSlackMessage;
|
|
2443
|
+
private handleCommand;
|
|
2444
|
+
protected getCommandList(): Promise<Array<{
|
|
2445
|
+
name: string;
|
|
2446
|
+
description?: string;
|
|
2447
|
+
agent?: string;
|
|
2448
|
+
model?: string;
|
|
2449
|
+
}>>;
|
|
2450
|
+
private syncBotCommands;
|
|
2324
2451
|
private toGatewayMessage;
|
|
2325
2452
|
private parseContent;
|
|
2453
|
+
private downloadFile;
|
|
2454
|
+
private downloadTextFile;
|
|
2326
2455
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2327
|
-
private processMessageAndGetSessionId;
|
|
2328
2456
|
private authTest;
|
|
2329
|
-
private postMessage;
|
|
2330
2457
|
private request;
|
|
2331
2458
|
}
|
|
2332
2459
|
|
|
@@ -2340,6 +2467,11 @@ interface FeishuBotConfig {
|
|
|
2340
2467
|
path: string;
|
|
2341
2468
|
port?: number;
|
|
2342
2469
|
};
|
|
2470
|
+
retry?: {
|
|
2471
|
+
maxAttempts?: number;
|
|
2472
|
+
initialDelay?: number;
|
|
2473
|
+
maxDelay?: number;
|
|
2474
|
+
};
|
|
2343
2475
|
}
|
|
2344
2476
|
interface FeishuMessageEvent {
|
|
2345
2477
|
type: string;
|
|
@@ -2376,9 +2508,12 @@ declare class FeishuPlugin extends BaseChannelPlugin {
|
|
|
2376
2508
|
private tenantAccessToken;
|
|
2377
2509
|
private tokenExpireTime;
|
|
2378
2510
|
private abortController;
|
|
2511
|
+
private processedMessageIds;
|
|
2512
|
+
private retryState;
|
|
2379
2513
|
constructor(id?: string);
|
|
2380
2514
|
protected doStart(): Promise<void>;
|
|
2381
2515
|
protected doStop(): Promise<void>;
|
|
2516
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2382
2517
|
send(message: GatewayMessage): Promise<string>;
|
|
2383
2518
|
getCapabilities(): {
|
|
2384
2519
|
supportsText: boolean;
|
|
@@ -2393,18 +2528,26 @@ declare class FeishuPlugin extends BaseChannelPlugin {
|
|
|
2393
2528
|
supportsHtml: boolean;
|
|
2394
2529
|
supportsDeliveryReceipt: boolean;
|
|
2395
2530
|
supportsReadReceipt: boolean;
|
|
2531
|
+
supportsSlashCommands: boolean;
|
|
2532
|
+
supportsNativeCommands: boolean;
|
|
2533
|
+
commandPrefix: string;
|
|
2396
2534
|
maxMessageLength: number;
|
|
2397
2535
|
maxMediaCount: number;
|
|
2398
2536
|
};
|
|
2399
2537
|
handleWebhookEvent(event: FeishuMessageEvent): Promise<void>;
|
|
2538
|
+
private refreshTenantAccessToken;
|
|
2539
|
+
private ensureTokenValid;
|
|
2540
|
+
private sendMessage;
|
|
2541
|
+
private sendImage;
|
|
2542
|
+
private sendFile;
|
|
2543
|
+
private uploadImage;
|
|
2544
|
+
private uploadFile;
|
|
2400
2545
|
private toGatewayMessage;
|
|
2401
2546
|
private parseContent;
|
|
2547
|
+
private downloadImage;
|
|
2548
|
+
private downloadFile;
|
|
2402
2549
|
private extractPostContent;
|
|
2403
2550
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2404
|
-
private processMessageAndGetSessionId;
|
|
2405
|
-
private refreshTenantAccessToken;
|
|
2406
|
-
private ensureTokenValid;
|
|
2407
|
-
private sendMessage;
|
|
2408
2551
|
}
|
|
2409
2552
|
|
|
2410
2553
|
interface WeChatBotConfig {
|
|
@@ -2419,6 +2562,11 @@ interface WeChatBotConfig {
|
|
|
2419
2562
|
path: string;
|
|
2420
2563
|
port?: number;
|
|
2421
2564
|
};
|
|
2565
|
+
retry?: {
|
|
2566
|
+
maxAttempts?: number;
|
|
2567
|
+
initialDelay?: number;
|
|
2568
|
+
maxDelay?: number;
|
|
2569
|
+
};
|
|
2422
2570
|
}
|
|
2423
2571
|
declare class WeChatPlugin extends BaseChannelPlugin {
|
|
2424
2572
|
readonly id: string;
|
|
@@ -2428,9 +2576,12 @@ declare class WeChatPlugin extends BaseChannelPlugin {
|
|
|
2428
2576
|
private accessToken;
|
|
2429
2577
|
private tokenExpireTime;
|
|
2430
2578
|
private abortController;
|
|
2579
|
+
private processedMessageIds;
|
|
2580
|
+
private retryState;
|
|
2431
2581
|
constructor(id?: string);
|
|
2432
2582
|
protected doStart(): Promise<void>;
|
|
2433
2583
|
protected doStop(): Promise<void>;
|
|
2584
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2434
2585
|
send(message: GatewayMessage): Promise<string>;
|
|
2435
2586
|
getCapabilities(): {
|
|
2436
2587
|
supportsText: boolean;
|
|
@@ -2445,19 +2596,23 @@ declare class WeChatPlugin extends BaseChannelPlugin {
|
|
|
2445
2596
|
supportsHtml: boolean;
|
|
2446
2597
|
supportsDeliveryReceipt: boolean;
|
|
2447
2598
|
supportsReadReceipt: boolean;
|
|
2599
|
+
supportsSlashCommands: boolean;
|
|
2600
|
+
supportsNativeCommands: boolean;
|
|
2601
|
+
commandPrefix: string;
|
|
2448
2602
|
maxMessageLength: number;
|
|
2449
2603
|
maxMediaCount: number;
|
|
2450
2604
|
};
|
|
2451
2605
|
handleWebhookMessage(xmlData: string): Promise<void>;
|
|
2452
|
-
private parseXmlMessage;
|
|
2453
|
-
private toGatewayMessage;
|
|
2454
|
-
private parseContent;
|
|
2455
|
-
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2456
|
-
private processMessageAndGetSessionId;
|
|
2457
2606
|
private refreshAccessToken;
|
|
2458
2607
|
private ensureTokenValid;
|
|
2459
2608
|
private sendOfficialMessage;
|
|
2460
2609
|
private sendWeComMessage;
|
|
2610
|
+
private sendImage;
|
|
2611
|
+
private uploadImage;
|
|
2612
|
+
private parseXmlMessage;
|
|
2613
|
+
private toGatewayMessage;
|
|
2614
|
+
private parseContent;
|
|
2615
|
+
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2461
2616
|
}
|
|
2462
2617
|
|
|
2463
2618
|
interface WebChatConfig {
|
|
@@ -2479,11 +2634,13 @@ declare class WebChatPlugin extends BaseChannelPlugin {
|
|
|
2479
2634
|
private connections;
|
|
2480
2635
|
private heartbeatInterval;
|
|
2481
2636
|
private abortController;
|
|
2637
|
+
private processedMessageIds;
|
|
2638
|
+
private sentMessages;
|
|
2482
2639
|
private wsServer;
|
|
2483
2640
|
constructor(id?: string);
|
|
2484
2641
|
protected doStart(): Promise<void>;
|
|
2485
|
-
private startWebSocketServer;
|
|
2486
2642
|
protected doStop(): Promise<void>;
|
|
2643
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2487
2644
|
send(message: GatewayMessage): Promise<string>;
|
|
2488
2645
|
getCapabilities(): {
|
|
2489
2646
|
supportsText: boolean;
|
|
@@ -2498,20 +2655,24 @@ declare class WebChatPlugin extends BaseChannelPlugin {
|
|
|
2498
2655
|
supportsHtml: boolean;
|
|
2499
2656
|
supportsDeliveryReceipt: boolean;
|
|
2500
2657
|
supportsReadReceipt: boolean;
|
|
2658
|
+
supportsSlashCommands: boolean;
|
|
2659
|
+
supportsNativeCommands: boolean;
|
|
2660
|
+
commandPrefix: string;
|
|
2501
2661
|
maxMessageLength: number;
|
|
2502
2662
|
maxMediaCount: number;
|
|
2503
2663
|
};
|
|
2504
2664
|
pushEvent(sessionId: string, event: SessionEventPayload): void;
|
|
2505
2665
|
getWebSocketServer(): GatewayWebSocketServer | null;
|
|
2506
2666
|
handleConnection(ws: WebSocket, userId: string): Promise<void>;
|
|
2667
|
+
getConnectionCount(): number;
|
|
2668
|
+
getWsServerConnectionCount(): number;
|
|
2669
|
+
private startWebSocketServer;
|
|
2507
2670
|
private handleWebSocketMessage;
|
|
2508
2671
|
private handleMessageAcknowledgment;
|
|
2509
2672
|
private handleChatMessage;
|
|
2510
2673
|
private startHeartbeat;
|
|
2511
2674
|
private findConnectionByUser;
|
|
2512
2675
|
private generateConnectionId;
|
|
2513
|
-
getConnectionCount(): number;
|
|
2514
|
-
getWsServerConnectionCount(): number;
|
|
2515
2676
|
}
|
|
2516
2677
|
|
|
2517
2678
|
interface SignalBotConfig {
|
|
@@ -2523,6 +2684,15 @@ interface SignalBotConfig {
|
|
|
2523
2684
|
path: string;
|
|
2524
2685
|
port?: number;
|
|
2525
2686
|
};
|
|
2687
|
+
polling?: {
|
|
2688
|
+
enabled: boolean;
|
|
2689
|
+
interval?: number;
|
|
2690
|
+
};
|
|
2691
|
+
retry?: {
|
|
2692
|
+
maxAttempts?: number;
|
|
2693
|
+
initialDelay?: number;
|
|
2694
|
+
maxDelay?: number;
|
|
2695
|
+
};
|
|
2526
2696
|
}
|
|
2527
2697
|
declare class SignalPlugin extends BaseChannelPlugin {
|
|
2528
2698
|
readonly id: string;
|
|
@@ -2532,9 +2702,13 @@ declare class SignalPlugin extends BaseChannelPlugin {
|
|
|
2532
2702
|
private abortController;
|
|
2533
2703
|
private lastTimestamp;
|
|
2534
2704
|
private pollingIntervalMs;
|
|
2705
|
+
private processedMessageIds;
|
|
2706
|
+
private sentMessages;
|
|
2707
|
+
private retryState;
|
|
2535
2708
|
constructor(id?: string);
|
|
2536
2709
|
protected doStart(): Promise<void>;
|
|
2537
2710
|
protected doStop(): Promise<void>;
|
|
2711
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2538
2712
|
send(message: GatewayMessage): Promise<string>;
|
|
2539
2713
|
getCapabilities(): {
|
|
2540
2714
|
supportsText: boolean;
|
|
@@ -2549,6 +2723,9 @@ declare class SignalPlugin extends BaseChannelPlugin {
|
|
|
2549
2723
|
supportsHtml: boolean;
|
|
2550
2724
|
supportsDeliveryReceipt: boolean;
|
|
2551
2725
|
supportsReadReceipt: boolean;
|
|
2726
|
+
supportsSlashCommands: boolean;
|
|
2727
|
+
supportsNativeCommands: boolean;
|
|
2728
|
+
commandPrefix: string;
|
|
2552
2729
|
maxMessageLength: number;
|
|
2553
2730
|
maxMediaCount: number;
|
|
2554
2731
|
};
|
|
@@ -2559,7 +2736,6 @@ declare class SignalPlugin extends BaseChannelPlugin {
|
|
|
2559
2736
|
private toGatewayMessage;
|
|
2560
2737
|
private parseContent;
|
|
2561
2738
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2562
|
-
private processMessageAndGetSessionId;
|
|
2563
2739
|
private getAccountInfo;
|
|
2564
2740
|
private receiveMessages;
|
|
2565
2741
|
private sendMessage;
|
|
@@ -2571,6 +2747,11 @@ interface NostrBotConfig {
|
|
|
2571
2747
|
privateKey?: string;
|
|
2572
2748
|
publicKey?: string;
|
|
2573
2749
|
timeout: number;
|
|
2750
|
+
retry?: {
|
|
2751
|
+
maxAttempts?: number;
|
|
2752
|
+
initialDelay?: number;
|
|
2753
|
+
maxDelay?: number;
|
|
2754
|
+
};
|
|
2574
2755
|
}
|
|
2575
2756
|
declare class NostrPlugin extends BaseChannelPlugin {
|
|
2576
2757
|
readonly id: string;
|
|
@@ -2579,13 +2760,16 @@ declare class NostrPlugin extends BaseChannelPlugin {
|
|
|
2579
2760
|
private botConfig;
|
|
2580
2761
|
private relayConnections;
|
|
2581
2762
|
private subscriptions;
|
|
2582
|
-
private eventHandlers;
|
|
2583
2763
|
private abortController;
|
|
2764
|
+
private processedEventIds;
|
|
2765
|
+
private sentMessages;
|
|
2584
2766
|
private relayReconnectAttempts;
|
|
2585
2767
|
private maxReconnectAttempts;
|
|
2768
|
+
private retryState;
|
|
2586
2769
|
constructor(id?: string);
|
|
2587
2770
|
protected doStart(): Promise<void>;
|
|
2588
2771
|
protected doStop(): Promise<void>;
|
|
2772
|
+
protected doHealthCheck(): Promise<boolean>;
|
|
2589
2773
|
send(message: GatewayMessage): Promise<string>;
|
|
2590
2774
|
getCapabilities(): {
|
|
2591
2775
|
supportsText: boolean;
|
|
@@ -2600,6 +2784,9 @@ declare class NostrPlugin extends BaseChannelPlugin {
|
|
|
2600
2784
|
supportsHtml: boolean;
|
|
2601
2785
|
supportsDeliveryReceipt: boolean;
|
|
2602
2786
|
supportsReadReceipt: boolean;
|
|
2787
|
+
supportsSlashCommands: boolean;
|
|
2788
|
+
supportsNativeCommands: boolean;
|
|
2789
|
+
commandPrefix: string;
|
|
2603
2790
|
maxMessageLength: number;
|
|
2604
2791
|
maxMediaCount: number;
|
|
2605
2792
|
};
|
|
@@ -2610,8 +2797,8 @@ declare class NostrPlugin extends BaseChannelPlugin {
|
|
|
2610
2797
|
private parseContent;
|
|
2611
2798
|
private findReplyTo;
|
|
2612
2799
|
protected buildSessionId(channelId: string, chatId: string, userId?: string): string;
|
|
2613
|
-
private processMessageAndGetSessionId;
|
|
2614
2800
|
private subscribeToRelay;
|
|
2801
|
+
private unsubscribeFromRelay;
|
|
2615
2802
|
private createEvent;
|
|
2616
2803
|
private computeEventId;
|
|
2617
2804
|
private signEvent;
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {v,Q,Z,_}from'./chunks/chunk-H425RRAV.mjs';export{p as AgentRegistryConfigSchema,k as AgentSyncConfigSchema,j as AuthConfigSchema,ga as BaseChannelPlugin,h as ChannelConfigSchema,ea as ChannelPluginLoader,qa as ChannelPluginRegistry,o as CircuitBreakerConfigSchema,m as ConnectionPoolConfigSchema,Z as DEFAULT_AGENT_REGISTRY_CONFIG,$ as DEFAULT_CONNECTION_POOL_CONFIG,_ as DEFAULT_SYNC_CONFIG,Y as DEFAULT_TOKEN_AUTH_CONFIG,X as DEFAULT_WEBSOCKET_SERVER_CONFIG,ia as DiscordPlugin,c as FeishuChannelConfigSchema,ka as FeishuPlugin,l as GatewayClusterConfigSchema,s as GatewayConfigSchema,sa as GatewayServer,r as GatewayServerConfigSchema,da as GatewaySessionManager,i as HTTPSConfigSchema,n as MessageQueueConfigSchema,aa as MessageRouter,ba as MessageStore,g as NostrChannelConfigSchema,oa as NostrPlugin,q as SessionConfigSchema,ca as SessionStore,f as SignalChannelConfigSchema,na as SignalPlugin,b as SlackChannelConfigSchema,ja as SlackPlugin,a as TelegramChannelConfigSchema,ha as TelegramPlugin,d as WeChatChannelConfigSchema,la as WeChatPlugin,e as WebChatChannelConfigSchema,ma as WebChatPlugin,y as clearConfigCache,T as convertToGatewayMessage,pa as createChannelPlugin,V as createDefaultSessionState,R as createGatewayMessage,S as createTextMessage,U as generateSessionId,W as generateSubscriptionId,N as getAgentAdapter,F as getAgentRegistryConfig,I as getAuthConfig,B as getChannelConfig,E as getCircuitBreakerConfig,J as getClusterConfig,w as getConfig,z as getConfigDirectory,C as getConnectionPoolConfig,K as getDefaultAgent,H as getHTTPSConfig,L as getLogLevel,D as getMessageQueueConfig,A as getServerConfig,G as getSessionConfig,ra as getSupportedPlatforms,O as hasAgentAdapter,x as isConfigLoaded,v as loadConfig,u as parsePartialConfig,P as requireAgentAdapter,M as setAgentAdapter,t as validateConfig}from'./chunks/chunk-H425RRAV.mjs';import {a as a$1}from'./chunks/chunk-7OFQ65NG.mjs';import {a as a$2}from'./chunks/chunk-HAMGVOQD.mjs';import {Fetch}from'@easbot/utils';var a=a$1.create({service:"gateway"}),m=class c extends Error{constructor(t,n,s){super(t);a$2(this,"type");a$2(this,"stage");a$2(this,"cause");this.type="GatewayInitializationError",this.stage=n,this.cause=s,Error.captureStackTrace&&Error.captureStackTrace(this,c);}};function H(c){let e=["ECONNRESET","EPIPE","ETIMEDOUT","ECONNREFUSED","ENOTFOUND","EHOSTUNREACH","ENETUNREACH"],t=c.code;return e.includes(t??"")}function et(){process.on("unhandledRejection",c=>{let e=c instanceof Error?c:new Error(String(c));H(e)||a.error("unhandled promise rejection",{error:e.message,stack:e.stack});}),process.on("uncaughtException",c=>{H(c)||(a.error("uncaught exception",{error:c.message,stack:c.stack}),process.exit(1));});}var x;(at=>{let c={initialized:false,initPromise:null,directory:".easbot",config:null},e,t={server:null,config:null,initialized:false,status:"stopped"};async function n(u={}){if(c.initialized)return;if(c.initPromise)return c.initPromise;let d={directory:u.directory??".easbot",printLogs:u.printLogs??false,logLevel:u.logLevel??"INFO"};return c.directory=d.directory,c.initPromise=(async()=>{let{Global:b}=await import('./chunks/global-Z3HUTR5L.mjs');try{await b.init();}catch(l){throw new m("Failed to initialize global directories","global",l instanceof Error?l:void 0)}try{await a$1.init({logDir:b.Path.log,print:d.printLogs,level:d.logLevel});}catch(l){throw new m("Failed to initialize log infrastructure","log",l instanceof Error?l:void 0)}try{et();}catch(l){throw new m("Failed to install unhandled exception handlers","server",l instanceof Error?l:void 0)}Fetch.hasProxyConfigured()&&(Fetch.enableProxy({connectTimeout:1e4,keepAliveTimeout:3e4}),a.info("global proxy enabled",{proxyUrl:Fetch.getProxyUrl()}));try{c.config=await v(d.directory);}catch(l){throw new m("Failed to load gateway configuration","config",l instanceof Error?l:void 0)}c.initialized=true,a.info("gateway runtime initialized",{directory:d.directory,logLevel:d.logLevel});})(),c.initPromise}at.init=n;function s(){return c.initialized}at.isInitialized=s;function r(){return e||(e=async()=>{if(!c.initialized)throw new m("Gateway not initialized. Call init() first.","server");let u=Q(),d=await v(u.directory);return d.server?.enabled?(t={server:null,config:d,initialized:true,status:"stopped"},a.info("gateway initialized",{port:d.server?.port,hostname:d.server?.hostname}),t):(a.debug("gateway server disabled or not configured"),{server:null,config:d,initialized:true,status:"stopped"})}),e}function i(){return r()()}at.state=i;async function o(){return (await i()).server}at.get=o;async function p(){return (await i()).config?.server?.enabled??false}at.isEnabled=p;async function G(){return (await i()).config}at.config=G;function nt(){return t.status}at.getStatus=nt;async function O(u){a.debug("Gateway.start: called"),c.initialized||(a.debug("Gateway.start: calling init()"),await n(),a.debug("Gateway.start: init() completed")),a.debug("Gateway.start: calling state()");let d=await i();if(a.debug("Gateway.start: state() completed",{status:d.status}),!(d.config?.server?.enabled??true))throw a.warn("gateway server is disabled"),new Error("Gateway server is disabled");if(t.status==="running"){a.info("gateway server is already running");return}if(t.status==="starting"){a.info("gateway server is starting");return}t.status="starting",a.debug("Gateway.start: status set to starting");try{let l={...d.config?.server,...u};a.debug("gateway start: creating server with config",{port:l.port,hostname:l.hostname,path:l.path,https:l.https?.enabled}),a.debug("Gateway.start: calling createGatewayServer");let I=await D(l);a.debug("Gateway.start: createGatewayServer completed"),a.debug("gateway start: server created, updating state"),t.server=I,t.status="running",t.error=void 0,a.info("gateway server started",{port:l.port,hostname:l.hostname});}catch(l){throw t.status="error",t.error=l instanceof Error?l.message:String(l),a.error("failed to start gateway server",{error:t.error}),l}}at.start=O;async function F(){if(t.status==="stopped"){a.info("gateway server is already stopped");return}if(t.status==="stopping"){a.info("gateway server is stopping");return}t.status="stopping";try{t.server&&await t.server.stop(),t.server=null,t.status="stopped",t.error=void 0,await a$1.close(),a.info("gateway server stopped");}catch(u){throw t.status="error",t.error=u instanceof Error?u.message:String(u),a.error("failed to stop gateway server",{error:t.error}),u}}at.stop=F;async function st(u){a.info("restarting gateway server"),(t.status==="running"||t.status==="starting")&&await F(),await O(u);}at.restart=st;async function rt(){let u=Q(),d=await v(u.directory);return t.config=d,c.config=d,a.info("gateway config reloaded"),d}at.reloadConfig=rt;async function D(u,d){a.debug("createGatewayServer: starting");let{GatewayServer:b}=await import('./chunks/server-QOFBCSK5.mjs');a.debug("createGatewayServer: GatewayServer imported");let l=new b(u);a.debug("createGatewayServer: server instance created"),a.debug("createGatewayServer: created server instance, calling start()");let I=d?.startupTimeout??3e4;if(await(async()=>{let A=new Promise((v,q)=>{setTimeout(()=>{q(new Error(`Gateway server startup timeout after ${I}ms`));},I);});try{a.debug("createGatewayServer: calling server.start()"),await Promise.race([l.start(),A]),a.debug("createGatewayServer: server.start() completed");}catch(v){a.error("gateway server start failed, attempting cleanup",{error:v instanceof Error?v.message:String(v)});try{await l.stop();}catch{}throw v}})(),d?.onStarted)try{await d.onStarted(l);}catch(A){a.warn("server started but onStarted callback failed",{error:A instanceof Error?A.message:String(A)});}return a.info("gateway server created and started",{port:u.port,hostname:u.hostname}),l}at.createGatewayServer=D;})(x||(x={}));var f=a$1.create({service:"gateway:agent-registry"}),T=class{constructor(e={}){a$2(this,"config");a$2(this,"agents",new Map);a$2(this,"heartbeatTimer",null);a$2(this,"roundRobinIndex",0);this.config={...Z,...e};}async register(e){if(this.agents.has(e.id))throw new Error(`Agent with ID "${e.id}" is already registered`);if(this.agents.size>=this.config.maxAgents)throw new Error(`Maximum number of agents (${this.config.maxAgents}) reached`);let t=Date.now(),n={...e,status:"healthy",lastHeartbeat:t,registeredAt:t,connectionCount:0};this.agents.set(e.id,n),f.info("Agent registered",{agentId:e.id,name:e.name,capabilities:e.capabilities,address:e.address,totalAgents:this.agents.size});}async deregister(e){let t=this.agents.get(e);if(!t){f.warn("Attempted to deregister unknown agent",{agentId:e});return}this.agents.delete(e),f.info("Agent deregistered",{agentId:e,name:t.name,totalAgents:this.agents.size});}async heartbeat(e,t){let n=this.agents.get(e);if(!n)throw f.warn("Heartbeat received from unknown agent",{agentId:e}),new Error(`Agent "${e}" is not registered`);n.lastHeartbeat=Date.now(),n.status="healthy",t&&(n.metadata={...n.metadata,...t}),f.debug("Agent heartbeat received",{agentId:e,lastHeartbeat:n.lastHeartbeat});}getAgent(e){return this.agents.get(e)}getAllAgents(){return Array.from(this.agents.values())}getHealthyAgents(){return this.getAllAgents().filter(e=>e.status==="healthy")}selectAgent(e){let{strategy:t,capabilities:n,healthyOnly:s=true}=e,r=s?this.getHealthyAgents():this.getAllAgents();if(n&&n.length>0&&(r=r.filter(o=>n.every(p=>o.capabilities.includes(p)))),r.length===0){f.warn("No agents available for selection",{strategy:t,capabilities:n,healthyOnly:s,totalAgents:this.agents.size});return}let i;switch(t){case "random":i=this.selectRandom(r);break;case "round-robin":i=this.selectRoundRobin(r);break;case "least-connections":i=this.selectLeastConnections(r);break;default:i=this.selectRandom(r);}return f.debug("Agent selected",{agentId:i.id,strategy:t,connectionCount:i.connectionCount}),i}incrementConnection(e){let t=this.agents.get(e);t&&(t.connectionCount++,f.debug("Agent connection incremented",{agentId:e,connectionCount:t.connectionCount}));}decrementConnection(e){let t=this.agents.get(e);t&&t.connectionCount>0&&(t.connectionCount--,f.debug("Agent connection decremented",{agentId:e,connectionCount:t.connectionCount}));}startHeartbeatCheck(){if(this.heartbeatTimer){f.warn("Heartbeat check is already running");return}f.info("Starting heartbeat check",{interval:this.config.heartbeatCheckInterval,timeout:this.config.heartbeatTimeout}),this.heartbeatTimer=setInterval(()=>this.checkHeartbeats(),this.config.heartbeatCheckInterval);}stopHeartbeatCheck(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,f.info("Heartbeat check stopped"));}checkHeartbeats(){let e=Date.now(),{heartbeatTimeout:t,autoDeregisterTimeout:n}=this.config,s=[],r=0;for(let[i,o]of this.agents.entries()){let p=e-o.lastHeartbeat;if(p>n){s.push(i);continue}p>t&&o.status==="healthy"&&(o.status="unhealthy",r++,f.warn("Agent marked as unhealthy due to heartbeat timeout",{agentId:i,lastHeartbeat:o.lastHeartbeat,timeSinceLastHeartbeat:p,timeout:t}));}for(let i of s){let o=this.agents.get(i);o&&(f.info("Auto-deregistering agent due to timeout",{agentId:i,name:o.name,lastHeartbeat:o.lastHeartbeat,timeout:n}),this.agents.delete(i));}(r>0||s.length>0)&&f.info("Heartbeat check completed",{unhealthyCount:r,deregisteredCount:s.length,totalAgents:this.agents.size});}selectRandom(e){let t=Math.floor(Math.random()*e.length);return e[t]}selectRoundRobin(e){this.roundRobinIndex=this.roundRobinIndex%e.length;let t=e[this.roundRobinIndex];return this.roundRobinIndex++,t}selectLeastConnections(e){return e.reduce((t,n)=>n.connectionCount<t.connectionCount?n:t)}getStats(){let e=this.getAllAgents();return {totalAgents:e.length,healthyAgents:e.filter(t=>t.status==="healthy").length,unhealthyAgents:e.filter(t=>t.status==="unhealthy").length,offlineAgents:e.filter(t=>t.status==="offline").length,totalConnections:e.reduce((t,n)=>t+n.connectionCount,0)}}setAgentStatus(e,t){let n=this.agents.get(e);n&&(n.status=t);}setLastHeartbeat(e,t){let n=this.agents.get(e);n&&(n.lastHeartbeat=t);}};var h=a$1.create({service:"gateway:agent-sync-manager"}),M=class{constructor(e){a$2(this,"config");a$2(this,"registry");a$2(this,"localNodeId");a$2(this,"localNodeName");a$2(this,"remoteNodes",new Map);a$2(this,"remoteAgents",new Map);a$2(this,"syncTimer",null);a$2(this,"running",false);this.registry=e.registry,this.localNodeId=e.localNodeId,this.localNodeName=e.localNodeName,this.config={..._,...e.config};}async start(){if(this.running){h.warn("Agent sync manager is already running");return}h.info("Starting agent sync manager",{localNodeId:this.localNodeId,mode:this.config.mode,interval:this.config.interval,remoteNodes:this.config.remoteNodes.length});for(let e of this.config.remoteNodes)this.remoteNodes.set(e.id,{info:{id:e.id,name:e.id,address:e.address,port:e.port,lastSyncAt:0,status:"unknown"},lastSyncAt:0,status:"synced"});(this.config.mode==="pull"||this.config.mode==="both")&&(this.syncTimer=setInterval(()=>this.pullFromAllNodes(),this.config.interval)),this.running=true,h.info("Agent sync manager started");}async stop(){if(!this.running){h.warn("Agent sync manager is not running");return}h.info("Stopping agent sync manager"),this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=null),this.remoteNodes.clear(),this.remoteAgents.clear(),this.running=false,h.info("Agent sync manager stopped");}async pullFromAllNodes(){for(let[e]of this.remoteNodes.entries())try{await this.pullFromNode(e);}catch(t){h.error("Failed to pull from node",{nodeId:e,error:t.message});}}async pullFromNode(e){let t=this.remoteNodes.get(e);if(!t)throw new Error(`Unknown remote node: ${e}`);t.status="syncing";let n=this.config.remoteNodes.find(s=>s.id===e);if(!n)throw new Error(`Remote node not found in config: ${e}`);h.debug("Pulling agent list from node",{nodeId:e,address:n.address});try{let s=`http://${n.address}:${n.port}/sync/agents`,r=await Fetch.get(s,{headers:{"Content-Type":"application/json","X-Gateway-Node-Id":this.localNodeId}});if(!r.ok)throw new Error(`HTTP ${r.status}`);let i=r.data.agents||[];for(let o of i)o.sourceGatewayId=e,this.remoteAgents.set(o.id,o);return t.lastSyncAt=Date.now(),t.status="synced",t.info.lastSyncAt=t.lastSyncAt,t.info.status="online",delete t.error,h.info("Pulled agent list from node",{nodeId:e,agentCount:i.length,lastSyncAt:t.lastSyncAt}),i}catch(s){throw t.status="error",t.error=s.message,t.info.status="offline",h.error("Failed to pull from node",{nodeId:e,error:s.message}),s}}async pushEvent(e){if(this.config.mode!=="push"&&this.config.mode!=="both")return;let t=[];for(let[n]of this.remoteNodes.entries())t.push(this.pushToNode(n,e));await Promise.allSettled(t);}async pushToNode(e,t){let n=this.config.remoteNodes.find(s=>s.id===e);if(!n){h.warn("Unknown remote node for push",{nodeId:e});return}try{let s=`http://${n.address}:${n.port}/sync/events`,r=await Fetch.post(s,t,{headers:{"Content-Type":"application/json","X-Gateway-Node-Id":this.localNodeId}});if(!r.ok)throw new Error(`HTTP ${r.status}`);h.debug("Pushed event to node",{nodeId:e,eventType:t.type});}catch(s){h.error("Failed to push to node",{nodeId:e,eventType:t.type,error:s.message});}}async handleSyncMessage(e){switch(h.debug("Received sync message",{type:e.type,sourceNodeId:e.sourceNodeId}),e.type){case "agent_list_request":await this.handleAgentListRequest(e);break;case "agent_list_response":await this.handleAgentListResponse(e);break;case "agent_register":await this.handleAgentRegister(e);break;case "agent_deregister":await this.handleAgentDeregister(e);break;case "agent_heartbeat":await this.handleAgentHeartbeat(e);break;case "agent_status_change":await this.handleAgentStatusChange(e);break;default:h.warn("Unknown sync message type",{type:e.type});}}async handleAgentListRequest(e){let t=this.getLocalAgentsForSync(),n={type:"agent_list_response",sourceNodeId:this.localNodeId,timestamp:Date.now(),requestId:e.requestId,agents:t,fullList:true,syncAt:Date.now()};await this.pushToNode(e.sourceNodeId,n);}async handleAgentListResponse(e){for(let t of e.agents)this.remoteAgents.set(t.id,t);h.info("Received agent list response",{sourceNodeId:e.sourceNodeId,agentCount:e.agents.length});}async handleAgentRegister(e){let{agent:t}=e,n=this.remoteAgents.get(t.id);if(n){let s=this.resolveConflict(n,t);this.remoteAgents.set(t.id,s);}else this.remoteAgents.set(t.id,t);h.info("Remote agent registered",{agentId:t.id,name:t.name,sourceNodeId:e.sourceNodeId});}async handleAgentDeregister(e){let{agentId:t}=e;this.remoteAgents.delete(t),h.info("Remote agent deregistered",{agentId:t,sourceNodeId:e.sourceNodeId});}async handleAgentHeartbeat(e){let{agentId:t,heartbeatAt:n,status:s}=e,r=this.remoteAgents.get(t);r&&(r.updatedAt=n,r.status=s),h.debug("Remote agent heartbeat received",{agentId:t,status:s,sourceNodeId:e.sourceNodeId});}async handleAgentStatusChange(e){let{agentId:t,newStatus:n,changedAt:s}=e,r=this.remoteAgents.get(t);r&&(r.status=n,r.updatedAt=s),h.info("Remote agent status changed",{agentId:t,newStatus:n,sourceNodeId:e.sourceNodeId});}resolveConflict(e,t){switch(this.config.conflictResolution){case "latest":return t.updatedAt>e.updatedAt?t:e;case "local":return e;case "remote":return t;default:return t.updatedAt>e.updatedAt?t:e}}getLocalAgentsForSync(){return this.registry.getAllAgents().map(t=>({id:t.id,name:t.name,sourceGatewayId:this.localNodeId,address:t.address,capabilities:t.capabilities,status:t.status,updatedAt:t.lastHeartbeat,metadata:t.metadata}))}getMergedAgentList(){let e=new Map;for(let t of this.getLocalAgentsForSync())e.set(t.id,t);for(let[t,n]of this.remoteAgents.entries())e.has(t)||e.set(t,n);return Array.from(e.values())}getRemoteAgents(){return Array.from(this.remoteAgents.values())}getStats(){let e=this.registry.getAllAgents(),t=0,n=0;for(let r of this.remoteNodes.values())r.info.status==="online"?t++:n++;let s=null;for(let r of this.remoteNodes.values())r.lastSyncAt>(s||0)&&(s=r.lastSyncAt);return {localAgentCount:e.length,remoteAgentCount:this.remoteAgents.size,totalAgentCount:e.length+this.remoteAgents.size,onlineNodeCount:t,offlineNodeCount:n,lastSyncAt:s}}isRunning(){return this.running}addRemoteNode(e){this.remoteNodes.set(e.id,{info:{id:e.id,name:e.id,address:e.address,port:e.port,lastSyncAt:0,status:"unknown"},lastSyncAt:0,status:"synced"}),h.info("Remote node added",{nodeId:e.id,address:e.address});}removeRemoteNode(e){this.remoteNodes.delete(e);for(let[t,n]of this.remoteAgents.entries())n.sourceGatewayId===e&&this.remoteAgents.delete(t);h.info("Remote node removed",{nodeId:e});}};var N=class{constructor(e){a$2(this,"log");a$2(this,"config");a$2(this,"ws",null);a$2(this,"state","disconnected");a$2(this,"subscriptions",new Map);a$2(this,"messageCallbacks",new Set);a$2(this,"agentListCallbacks",new Set);a$2(this,"cachedAgentList",[]);a$2(this,"localAgentList",[]);a$2(this,"reconnectAttempts",0);a$2(this,"reconnectTimer",null);a$2(this,"heartbeatTimer",null);a$2(this,"agentListRequestId",null);a$2(this,"agentListRequestResolve",null);this.config={url:e.url,type:e.type,id:e.id??`client_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,reconnect:{enabled:e.reconnect?.enabled??true,maxAttempts:e.reconnect?.maxAttempts??5,delay:e.reconnect?.delay??3e3},heartbeat:{enabled:e.heartbeat?.enabled??true,interval:e.heartbeat?.interval??3e4}},this.log=a$1.create({service:`gateway:client:${this.config.id}`});}async connect(){if(this.state==="connected"||this.state==="connecting"){this.log.warn("already connected or connecting");return}return this.state="connecting",this.log.info("connecting to gateway",{url:this.config.url}),new Promise((e,t)=>{try{this.ws=new WebSocket(this.config.url),this.ws.onopen=()=>{this.state="connected",this.reconnectAttempts=0,this.log.info("connected to gateway"),this.config.heartbeat.enabled&&this.startHeartbeat(),this.resubscribeAll(),e();},this.ws.onmessage=n=>{this.handleMessage(n.data);},this.ws.onclose=n=>{this.handleClose(n.code,n.reason);},this.ws.onerror=n=>{this.log.error("WebSocket error",{error:String(n)}),this.state==="connecting"&&t(new Error("Connection failed"));};}catch(n){this.state="disconnected",t(n);}})}async disconnect(){this.state!=="disconnected"&&(this.log.info("disconnecting from gateway"),this.stopHeartbeat(),this.stopReconnect(),this.ws&&(this.ws.close(1e3,"Client disconnect"),this.ws=null),this.state="disconnected",this.log.info("disconnected from gateway"));}async subscribe(e,t){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"subscribe",sessionId:e,backendSessionId:t,clientId:this.config.id}),this.log.info("subscribed to session",{sessionId:e,backendSessionId:t});}async unsubscribe(e){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"unsubscribe",sessionId:e,clientId:this.config.id}),this.subscriptions.delete(e),this.log.info("unsubscribed from session",{sessionId:e});}async send(e){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"message",message:e});}onMessage(e){this.messageCallbacks.add(e);}offMessage(e){this.messageCallbacks.delete(e);}getState(){return this.state}getId(){return this.config.id}getSubscriptions(){return [...this.subscriptions.keys()]}setLocalAgents(e){this.localAgentList=e,this.updateMergedAgentList();}async fetchAgentList(){if(this.state!=="connected")throw new Error("Not connected to gateway");return new Promise((e,t)=>{let n=`req_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.agentListRequestId=n,this.agentListRequestResolve=e,this.sendData({type:"agent_list_request",requestId:n}),setTimeout(()=>{this.agentListRequestId===n&&(this.agentListRequestId=null,this.agentListRequestResolve=null,t(new Error("Agent list request timeout")));},1e4);})}getConnectableAgents(e={}){let{localAgents:t,preferLocal:n=true,filterOffline:s=true}=e,r=t||this.localAgentList,i=this.cachedAgentList,o=this.mergeAgentLists(r,i,n);return s?o.filter(p=>p.status!=="offline"):o}onAgentListChange(e){this.agentListCallbacks.add(e);}offAgentListChange(e){this.agentListCallbacks.delete(e);}mergeAgentLists(e,t,n){let s=new Map,r=n?t:e,i=n?e:t;for(let o of r)s.set(o.id,o);for(let o of i)s.set(o.id,o);return Array.from(s.values())}updateMergedAgentList(){let e=this.getConnectableAgents({filterOffline:false});for(let t of this.agentListCallbacks)try{t(e);}catch(n){this.log.error("agent list callback error",{error:String(n)});}}handleAgentListResponse(e,t){t&&this.agentListRequestId===t&&this.agentListRequestResolve&&(this.agentListRequestId=null,this.agentListRequestResolve(e),this.agentListRequestResolve=null),this.cachedAgentList=e,this.updateMergedAgentList(),this.log.debug("received agent list",{count:e.length});}sendData(e){if(!this.ws||this.ws.readyState!==WebSocket.OPEN){this.log.warn("WebSocket not ready, cannot send");return}this.ws.send(JSON.stringify(e));}handleMessage(e){try{let t=JSON.parse(e);switch(t.type){case "message":this.handleGatewayMessage(t.message);break;case "subscribed":this.subscriptions.set(t.sessionId,t.subscription);break;case "unsubscribed":this.subscriptions.delete(t.sessionId);break;case "pong":break;case "agent_list_response":this.handleAgentListResponse(t.agents||[],t.requestId);break;case "agent_update":this.handleAgentUpdate(t.agent,t.action);break;default:this.log.debug("unknown message type",{type:t.type});}}catch(t){this.log.error("failed to parse message",{error:String(t)});}}handleAgentUpdate(e,t){switch(t){case "add":case "update":{let n=this.cachedAgentList.findIndex(s=>s.id===e.id);n>=0?this.cachedAgentList[n]=e:this.cachedAgentList.push(e);break}case "remove":this.cachedAgentList=this.cachedAgentList.filter(n=>n.id!==e.id);break}this.updateMergedAgentList();}handleGatewayMessage(e){for(let t of this.messageCallbacks)try{t(e);}catch(n){this.log.error("message callback error",{error:String(n)});}}handleClose(e,t){this.log.info("connection closed",{code:e,reason:t}),this.state="disconnected",this.ws=null,this.stopHeartbeat(),this.config.reconnect.enabled&&this.scheduleReconnect();}scheduleReconnect(){if(this.reconnectAttempts>=this.config.reconnect.maxAttempts){this.log.error("max reconnect attempts reached");return}this.reconnectAttempts++,this.state="reconnecting";let e=this.config.reconnect.delay*this.reconnectAttempts;this.log.info("scheduling reconnect",{attempt:this.reconnectAttempts,delay:e}),this.reconnectTimer=setTimeout(async()=>{try{await this.connect();}catch(t){this.log.error("reconnect failed",{error:String(t)});}},e);}stopReconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{this.state==="connected"&&this.sendData({type:"ping"});},this.config.heartbeat.interval);}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null);}async resubscribeAll(){for(let e of this.subscriptions.keys())try{await this.subscribe(e);}catch(t){this.log.error("failed to resubscribe",{sessionId:e,error:String(t)});}}getHttpUrl(){return this.config.url.replace(/^ws:/,"http:").replace(/^wss:/,"https:").replace(/\/$/,"")}async httpRequest(e,t={}){let n=`${this.getHttpUrl()}${e}`,s=t.method||"GET",{signal:r,...i}=t,o=await Fetch.request(n,{method:s,...i,headers:{"Content-Type":"application/json",...i.headers},...r?{signal:r}:{}});if(!o.ok){let p=o.data,G=typeof p=="object"?JSON.stringify(p):String(p||"Unknown error");throw new Error(`HTTP ${o.status}: ${G}`)}return o.data}async healthCheck(){return this.httpRequest("/health")}async getStatus(){return this.httpRequest("/status")}async listChannels(){return this.httpRequest("/channels")}async listContacts(e,t={}){let n=new URLSearchParams({platform:e,limit:String(t.limit??100),offset:String(t.offset??0)});return this.httpRequest(`/contacts?${n}`)}async getContact(e){return this.httpRequest(`/contacts/${encodeURIComponent(e)}`)}async getSession(e){return this.httpRequest(`/sessions/${encodeURIComponent(e)}`)}async createSession(e){return this.httpRequest("/session",{method:"POST",body:JSON.stringify(e??{})})}async getOrCreateSession(e){if(e.sessionId)try{return await this.getSession(e.sessionId),{sessionId:e.sessionId,created:!1}}catch{this.log.debug("session not found, will create new",{sessionId:e.sessionId});}if(e.platform||e.channel||e.userId){let n=e.chatId??e.userId;try{let i=await this.listSessions({platform:e.platform,channelId:e.channel,userId:e.userId,chatId:n});if(i.sessions.length>0){let o=i.sessions[0];if(o)return this.log.info("found existing session",{sessionId:o.id,channel:e.channel,userId:e.userId,chatId:n}),{sessionId:o.id,created:!1}}}catch(i){this.log.warn("failed to search sessions",{error:String(i)});}let s={channel:{platform:e.platform,channelId:e.channel,userId:e.userId,chatId:n}},r=await this.createSession(s);return this.log.info("session created",{sessionId:r.id,params:s}),{sessionId:r.id,created:true}}let t=await this.createSession({channel:{platform:"api",channelId:"default"}});return this.log.info("session created (default)",{sessionId:t.id}),{sessionId:t.id,created:true}}async listSessions(e={}){let t=new URLSearchParams;return t.set("limit",String(e.limit??100)),t.set("offset",String(e.offset??0)),e.platform&&t.set("platform",e.platform),e.channelId&&t.set("channelId",e.channelId),e.userId&&t.set("userId",e.userId),e.chatId&&t.set("chatId",e.chatId),this.httpRequest(`/sessions?${t}`)}async sendMessage(e,t){return this.httpRequest(`/session/${encodeURIComponent(e)}/prompt`,{method:"POST",body:JSON.stringify(t)})}};async function zt(c){let{Log:e}=await import('./chunks/log-MIT4H7S5.mjs'),t=false;await e.init({logDir:c.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:c.print??false,dev:c.dev??t,level:c.level??("INFO")});}
|
|
2
|
-
export{T as AgentRegistry,M as AgentSyncManager,x as Gateway,N as GatewayClient,
|
|
1
|
+
import {Q,v,R,_ as _$1,$}from'./chunks/chunk-OBFSXYWV.mjs';export{p as AgentRegistryConfigSchema,k as AgentSyncConfigSchema,j as AuthConfigSchema,ha as BaseChannelPlugin,h as ChannelConfigSchema,fa as ChannelPluginLoader,ra as ChannelPluginRegistry,o as CircuitBreakerConfigSchema,m as ConnectionPoolConfigSchema,_ as DEFAULT_AGENT_REGISTRY_CONFIG,aa as DEFAULT_CONNECTION_POOL_CONFIG,$ as DEFAULT_SYNC_CONFIG,Z as DEFAULT_TOKEN_AUTH_CONFIG,Y as DEFAULT_WEBSOCKET_SERVER_CONFIG,ja as DiscordPlugin,c as FeishuChannelConfigSchema,la as FeishuPlugin,l as GatewayClusterConfigSchema,s as GatewayConfigSchema,ta as GatewayServer,r as GatewayServerConfigSchema,ea as GatewaySessionManager,i as HTTPSConfigSchema,n as MessageQueueConfigSchema,ba as MessageRouter,ca as MessageStore,g as NostrChannelConfigSchema,pa as NostrPlugin,q as SessionConfigSchema,da as SessionStore,f as SignalChannelConfigSchema,oa as SignalPlugin,b as SlackChannelConfigSchema,ka as SlackPlugin,a as TelegramChannelConfigSchema,ia as TelegramPlugin,d as WeChatChannelConfigSchema,ma as WeChatPlugin,e as WebChatChannelConfigSchema,na as WebChatPlugin,y as clearConfigCache,U as convertToGatewayMessage,qa as createChannelPlugin,W as createDefaultSessionState,S as createGatewayMessage,T as createTextMessage,V as generateSessionId,X as generateSubscriptionId,N as getAgentAdapter,F as getAgentRegistryConfig,I as getAuthConfig,B as getChannelConfig,E as getCircuitBreakerConfig,J as getClusterConfig,w as getConfig,z as getConfigDirectory,C as getConnectionPoolConfig,K as getDefaultAgent,H as getHTTPSConfig,L as getLogLevel,D as getMessageQueueConfig,A as getServerConfig,G as getSessionConfig,sa as getSupportedPlatforms,O as hasAgentAdapter,x as isConfigLoaded,v as loadConfig,u as parsePartialConfig,P as requireAgentAdapter,M as setAgentAdapter,t as validateConfig}from'./chunks/chunk-OBFSXYWV.mjs';import {b,a as a$1}from'./chunks/chunk-RGPJTZUB.mjs';import {Fetch}from'@easbot/utils';var a=b.create({service:"gateway"}),C=class c extends Error{constructor(t,n,s){super(t);a$1(this,"type");a$1(this,"stage");a$1(this,"cause");this.type="GatewayInitializationError",this.stage=n,this.cause=s,Error.captureStackTrace&&Error.captureStackTrace(this,c);}};function _(c){let e=["ECONNRESET","EPIPE","ETIMEDOUT","ECONNREFUSED","ENOTFOUND","EHOSTUNREACH","ENETUNREACH"],t=c.code;return e.includes(t??"")}function tt(){process.on("unhandledRejection",c=>{let e=c instanceof Error?c:new Error(String(c));_(e)||a.error("unhandled promise rejection",{error:e.message,stack:e.stack});}),process.on("uncaughtException",c=>{_(c)||(a.error("uncaught exception",{error:c.message,stack:c.stack}),process.exit(1));});}var x;(it=>{let c={initialized:false,initPromise:null,directory:".easbot",config:null},e,t={server:null,config:null,initialized:false,status:"stopped"};async function n(u={}){if(c.initialized)return;if(c.initPromise)return c.initPromise;let d={directory:u.directory??".easbot",printLogs:u.printLogs??false,logLevel:u.logLevel??"INFO"};return c.directory=d.directory,c.initPromise=(async()=>{let w=Q();try{await b.init({logDir:w.Path.log,print:d.printLogs,level:d.logLevel});}catch(l){throw new C("Failed to initialize log infrastructure","log",l instanceof Error?l:void 0)}try{tt();}catch(l){throw new C("Failed to install unhandled exception handlers","server",l instanceof Error?l:void 0)}Fetch.hasProxyConfigured()&&(Fetch.enableProxy({connectTimeout:1e4,keepAliveTimeout:3e4}),a.info("global proxy enabled",{proxyUrl:Fetch.getProxyUrl()}));try{c.config=await v(d.directory);}catch(l){throw new C("Failed to load gateway configuration","config",l instanceof Error?l:void 0)}c.initialized=true,a.info("gateway runtime initialized",{directory:d.directory,logLevel:d.logLevel});})(),c.initPromise}it.init=n;function s(){return c.initialized}it.isInitialized=s;function r(){return e||(e=async()=>{if(!c.initialized)throw new C("Gateway not initialized. Call init() first.","server");let u=R(),d=await v(u.directory);return d.server?.enabled?(t={server:null,config:d,initialized:true,status:"stopped"},a.info("gateway initialized",{port:d.server?.port,hostname:d.server?.hostname}),t):(a.debug("gateway server disabled or not configured"),{server:null,config:d,initialized:true,status:"stopped"})}),e}function i(){return r()()}it.state=i;async function o(){return (await i()).server}it.get=o;async function p(){return (await i()).config?.server?.enabled??false}it.isEnabled=p;async function G(){return (await i()).config}it.config=G;function st(){return t.status}it.getStatus=st;async function F(u){a.debug("Gateway.start: called"),c.initialized||(a.debug("Gateway.start: calling init()"),await n(),a.debug("Gateway.start: init() completed")),a.debug("Gateway.start: calling state()");let d=await i();if(a.debug("Gateway.start: state() completed",{status:d.status}),!(d.config?.server?.enabled??true))throw a.warn("gateway server is disabled"),new Error("Gateway server is disabled");if(t.status==="running"){a.info("gateway server is already running");return}if(t.status==="starting"){a.info("gateway server is starting");return}t.status="starting",a.debug("Gateway.start: status set to starting");try{let l={...d.config?.server,...u};a.debug("gateway start: creating server with config",{port:l.port,hostname:l.hostname,path:l.path,https:l.https?.enabled}),a.debug("Gateway.start: calling createGatewayServer");let I=await q(l);a.debug("Gateway.start: createGatewayServer completed"),a.debug("gateway start: server created, updating state"),t.server=I,t.status="running",t.error=void 0,a.info("gateway server started",{port:l.port,hostname:l.hostname});}catch(l){throw t.status="error",t.error=l instanceof Error?l.message:String(l),a.error("failed to start gateway server",{error:t.error}),l}}it.start=F;async function D(){if(t.status==="stopped"){a.info("gateway server is already stopped");return}if(t.status==="stopping"){a.info("gateway server is stopping");return}t.status="stopping";try{t.server&&await t.server.stop(),t.server=null,t.status="stopped",t.error=void 0,await b.close(),a.info("gateway server stopped");}catch(u){throw t.status="error",t.error=u instanceof Error?u.message:String(u),a.error("failed to stop gateway server",{error:t.error}),u}}it.stop=D;async function rt(u){a.info("restarting gateway server"),(t.status==="running"||t.status==="starting")&&await D(),await F(u);}it.restart=rt;async function at(){let u=R(),d=await v(u.directory);return t.config=d,c.config=d,a.info("gateway config reloaded"),d}it.reloadConfig=at;async function q(u,d){a.debug("createGatewayServer: starting");let{GatewayServer:w}=await import('./chunks/server-54GY5XXD.mjs');a.debug("createGatewayServer: GatewayServer imported");let l=new w(u);a.debug("createGatewayServer: server instance created"),a.debug("createGatewayServer: created server instance, calling start()");let I=d?.startupTimeout??3e4;if(await(async()=>{let b=new Promise((A,U)=>{setTimeout(()=>{U(new Error(`Gateway server startup timeout after ${I}ms`));},I);});try{a.debug("createGatewayServer: calling server.start()"),await Promise.race([l.start(),b]),a.debug("createGatewayServer: server.start() completed");}catch(A){a.error("gateway server start failed, attempting cleanup",{error:A instanceof Error?A.message:String(A)});try{await l.stop();}catch{}throw A}})(),d?.onStarted)try{await d.onStarted(l);}catch(b){a.warn("server started but onStarted callback failed",{error:b instanceof Error?b.message:String(b)});}return a.info("gateway server created and started",{port:u.port,hostname:u.hostname}),l}it.createGatewayServer=q;})(x||(x={}));var f=b.create({service:"gateway:agent-registry"}),T=class{constructor(e={}){a$1(this,"config");a$1(this,"agents",new Map);a$1(this,"heartbeatTimer",null);a$1(this,"roundRobinIndex",0);this.config={..._$1,...e};}async register(e){if(this.agents.has(e.id))throw new Error(`Agent with ID "${e.id}" is already registered`);if(this.agents.size>=this.config.maxAgents)throw new Error(`Maximum number of agents (${this.config.maxAgents}) reached`);let t=Date.now(),n={...e,status:"healthy",lastHeartbeat:t,registeredAt:t,connectionCount:0};this.agents.set(e.id,n),f.info("Agent registered",{agentId:e.id,name:e.name,capabilities:e.capabilities,address:e.address,totalAgents:this.agents.size});}async deregister(e){let t=this.agents.get(e);if(!t){f.warn("Attempted to deregister unknown agent",{agentId:e});return}this.agents.delete(e),f.info("Agent deregistered",{agentId:e,name:t.name,totalAgents:this.agents.size});}async heartbeat(e,t){let n=this.agents.get(e);if(!n)throw f.warn("Heartbeat received from unknown agent",{agentId:e}),new Error(`Agent "${e}" is not registered`);n.lastHeartbeat=Date.now(),n.status="healthy",t&&(n.metadata={...n.metadata,...t}),f.debug("Agent heartbeat received",{agentId:e,lastHeartbeat:n.lastHeartbeat});}getAgent(e){return this.agents.get(e)}getAllAgents(){return Array.from(this.agents.values())}getHealthyAgents(){return this.getAllAgents().filter(e=>e.status==="healthy")}selectAgent(e){let{strategy:t,capabilities:n,healthyOnly:s=true}=e,r=s?this.getHealthyAgents():this.getAllAgents();if(n&&n.length>0&&(r=r.filter(o=>n.every(p=>o.capabilities.includes(p)))),r.length===0){f.warn("No agents available for selection",{strategy:t,capabilities:n,healthyOnly:s,totalAgents:this.agents.size});return}let i;switch(t){case "random":i=this.selectRandom(r);break;case "round-robin":i=this.selectRoundRobin(r);break;case "least-connections":i=this.selectLeastConnections(r);break;default:i=this.selectRandom(r);}return f.debug("Agent selected",{agentId:i.id,strategy:t,connectionCount:i.connectionCount}),i}incrementConnection(e){let t=this.agents.get(e);t&&(t.connectionCount++,f.debug("Agent connection incremented",{agentId:e,connectionCount:t.connectionCount}));}decrementConnection(e){let t=this.agents.get(e);t&&t.connectionCount>0&&(t.connectionCount--,f.debug("Agent connection decremented",{agentId:e,connectionCount:t.connectionCount}));}startHeartbeatCheck(){if(this.heartbeatTimer){f.warn("Heartbeat check is already running");return}f.info("Starting heartbeat check",{interval:this.config.heartbeatCheckInterval,timeout:this.config.heartbeatTimeout}),this.heartbeatTimer=setInterval(()=>this.checkHeartbeats(),this.config.heartbeatCheckInterval);}stopHeartbeatCheck(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null,f.info("Heartbeat check stopped"));}checkHeartbeats(){let e=Date.now(),{heartbeatTimeout:t,autoDeregisterTimeout:n}=this.config,s=[],r=0;for(let[i,o]of this.agents.entries()){let p=e-o.lastHeartbeat;if(p>n){s.push(i);continue}p>t&&o.status==="healthy"&&(o.status="unhealthy",r++,f.warn("Agent marked as unhealthy due to heartbeat timeout",{agentId:i,lastHeartbeat:o.lastHeartbeat,timeSinceLastHeartbeat:p,timeout:t}));}for(let i of s){let o=this.agents.get(i);o&&(f.info("Auto-deregistering agent due to timeout",{agentId:i,name:o.name,lastHeartbeat:o.lastHeartbeat,timeout:n}),this.agents.delete(i));}(r>0||s.length>0)&&f.info("Heartbeat check completed",{unhealthyCount:r,deregisteredCount:s.length,totalAgents:this.agents.size});}selectRandom(e){let t=Math.floor(Math.random()*e.length);return e[t]}selectRoundRobin(e){this.roundRobinIndex=this.roundRobinIndex%e.length;let t=e[this.roundRobinIndex];return this.roundRobinIndex++,t}selectLeastConnections(e){return e.reduce((t,n)=>n.connectionCount<t.connectionCount?n:t)}getStats(){let e=this.getAllAgents();return {totalAgents:e.length,healthyAgents:e.filter(t=>t.status==="healthy").length,unhealthyAgents:e.filter(t=>t.status==="unhealthy").length,offlineAgents:e.filter(t=>t.status==="offline").length,totalConnections:e.reduce((t,n)=>t+n.connectionCount,0)}}setAgentStatus(e,t){let n=this.agents.get(e);n&&(n.status=t);}setLastHeartbeat(e,t){let n=this.agents.get(e);n&&(n.lastHeartbeat=t);}};var h=b.create({service:"gateway:agent-sync-manager"}),M=class{constructor(e){a$1(this,"config");a$1(this,"registry");a$1(this,"localNodeId");a$1(this,"localNodeName");a$1(this,"remoteNodes",new Map);a$1(this,"remoteAgents",new Map);a$1(this,"syncTimer",null);a$1(this,"running",false);this.registry=e.registry,this.localNodeId=e.localNodeId,this.localNodeName=e.localNodeName,this.config={...$,...e.config};}async start(){if(this.running){h.warn("Agent sync manager is already running");return}h.info("Starting agent sync manager",{localNodeId:this.localNodeId,mode:this.config.mode,interval:this.config.interval,remoteNodes:this.config.remoteNodes.length});for(let e of this.config.remoteNodes)this.remoteNodes.set(e.id,{info:{id:e.id,name:e.id,address:e.address,port:e.port,lastSyncAt:0,status:"unknown"},lastSyncAt:0,status:"synced"});(this.config.mode==="pull"||this.config.mode==="both")&&(this.syncTimer=setInterval(()=>this.pullFromAllNodes(),this.config.interval)),this.running=true,h.info("Agent sync manager started");}async stop(){if(!this.running){h.warn("Agent sync manager is not running");return}h.info("Stopping agent sync manager"),this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=null),this.remoteNodes.clear(),this.remoteAgents.clear(),this.running=false,h.info("Agent sync manager stopped");}async pullFromAllNodes(){for(let[e]of this.remoteNodes.entries())try{await this.pullFromNode(e);}catch(t){h.error("Failed to pull from node",{nodeId:e,error:t.message});}}async pullFromNode(e){let t=this.remoteNodes.get(e);if(!t)throw new Error(`Unknown remote node: ${e}`);t.status="syncing";let n=this.config.remoteNodes.find(s=>s.id===e);if(!n)throw new Error(`Remote node not found in config: ${e}`);h.debug("Pulling agent list from node",{nodeId:e,address:n.address});try{let s=`http://${n.address}:${n.port}/sync/agents`,r=await Fetch.get(s,{headers:{"Content-Type":"application/json","X-Gateway-Node-Id":this.localNodeId}});if(!r.ok)throw new Error(`HTTP ${r.status}`);let i=r.data.agents||[];for(let o of i)o.sourceGatewayId=e,this.remoteAgents.set(o.id,o);return t.lastSyncAt=Date.now(),t.status="synced",t.info.lastSyncAt=t.lastSyncAt,t.info.status="online",delete t.error,h.info("Pulled agent list from node",{nodeId:e,agentCount:i.length,lastSyncAt:t.lastSyncAt}),i}catch(s){throw t.status="error",t.error=s.message,t.info.status="offline",h.error("Failed to pull from node",{nodeId:e,error:s.message}),s}}async pushEvent(e){if(this.config.mode!=="push"&&this.config.mode!=="both")return;let t=[];for(let[n]of this.remoteNodes.entries())t.push(this.pushToNode(n,e));await Promise.allSettled(t);}async pushToNode(e,t){let n=this.config.remoteNodes.find(s=>s.id===e);if(!n){h.warn("Unknown remote node for push",{nodeId:e});return}try{let s=`http://${n.address}:${n.port}/sync/events`,r=await Fetch.post(s,t,{headers:{"Content-Type":"application/json","X-Gateway-Node-Id":this.localNodeId}});if(!r.ok)throw new Error(`HTTP ${r.status}`);h.debug("Pushed event to node",{nodeId:e,eventType:t.type});}catch(s){h.error("Failed to push to node",{nodeId:e,eventType:t.type,error:s.message});}}async handleSyncMessage(e){switch(h.debug("Received sync message",{type:e.type,sourceNodeId:e.sourceNodeId}),e.type){case "agent_list_request":await this.handleAgentListRequest(e);break;case "agent_list_response":await this.handleAgentListResponse(e);break;case "agent_register":await this.handleAgentRegister(e);break;case "agent_deregister":await this.handleAgentDeregister(e);break;case "agent_heartbeat":await this.handleAgentHeartbeat(e);break;case "agent_status_change":await this.handleAgentStatusChange(e);break;default:h.warn("Unknown sync message type",{type:e.type});}}async handleAgentListRequest(e){let t=this.getLocalAgentsForSync(),n={type:"agent_list_response",sourceNodeId:this.localNodeId,timestamp:Date.now(),requestId:e.requestId,agents:t,fullList:true,syncAt:Date.now()};await this.pushToNode(e.sourceNodeId,n);}async handleAgentListResponse(e){for(let t of e.agents)this.remoteAgents.set(t.id,t);h.info("Received agent list response",{sourceNodeId:e.sourceNodeId,agentCount:e.agents.length});}async handleAgentRegister(e){let{agent:t}=e,n=this.remoteAgents.get(t.id);if(n){let s=this.resolveConflict(n,t);this.remoteAgents.set(t.id,s);}else this.remoteAgents.set(t.id,t);h.info("Remote agent registered",{agentId:t.id,name:t.name,sourceNodeId:e.sourceNodeId});}async handleAgentDeregister(e){let{agentId:t}=e;this.remoteAgents.delete(t),h.info("Remote agent deregistered",{agentId:t,sourceNodeId:e.sourceNodeId});}async handleAgentHeartbeat(e){let{agentId:t,heartbeatAt:n,status:s}=e,r=this.remoteAgents.get(t);r&&(r.updatedAt=n,r.status=s),h.debug("Remote agent heartbeat received",{agentId:t,status:s,sourceNodeId:e.sourceNodeId});}async handleAgentStatusChange(e){let{agentId:t,newStatus:n,changedAt:s}=e,r=this.remoteAgents.get(t);r&&(r.status=n,r.updatedAt=s),h.info("Remote agent status changed",{agentId:t,newStatus:n,sourceNodeId:e.sourceNodeId});}resolveConflict(e,t){switch(this.config.conflictResolution){case "latest":return t.updatedAt>e.updatedAt?t:e;case "local":return e;case "remote":return t;default:return t.updatedAt>e.updatedAt?t:e}}getLocalAgentsForSync(){return this.registry.getAllAgents().map(t=>({id:t.id,name:t.name,sourceGatewayId:this.localNodeId,address:t.address,capabilities:t.capabilities,status:t.status,updatedAt:t.lastHeartbeat,metadata:t.metadata}))}getMergedAgentList(){let e=new Map;for(let t of this.getLocalAgentsForSync())e.set(t.id,t);for(let[t,n]of this.remoteAgents.entries())e.has(t)||e.set(t,n);return Array.from(e.values())}getRemoteAgents(){return Array.from(this.remoteAgents.values())}getStats(){let e=this.registry.getAllAgents(),t=0,n=0;for(let r of this.remoteNodes.values())r.info.status==="online"?t++:n++;let s=null;for(let r of this.remoteNodes.values())r.lastSyncAt>(s||0)&&(s=r.lastSyncAt);return {localAgentCount:e.length,remoteAgentCount:this.remoteAgents.size,totalAgentCount:e.length+this.remoteAgents.size,onlineNodeCount:t,offlineNodeCount:n,lastSyncAt:s}}isRunning(){return this.running}addRemoteNode(e){this.remoteNodes.set(e.id,{info:{id:e.id,name:e.id,address:e.address,port:e.port,lastSyncAt:0,status:"unknown"},lastSyncAt:0,status:"synced"}),h.info("Remote node added",{nodeId:e.id,address:e.address});}removeRemoteNode(e){this.remoteNodes.delete(e);for(let[t,n]of this.remoteAgents.entries())n.sourceGatewayId===e&&this.remoteAgents.delete(t);h.info("Remote node removed",{nodeId:e});}};var N=class{constructor(e){a$1(this,"log");a$1(this,"config");a$1(this,"ws",null);a$1(this,"state","disconnected");a$1(this,"subscriptions",new Map);a$1(this,"messageCallbacks",new Set);a$1(this,"agentListCallbacks",new Set);a$1(this,"cachedAgentList",[]);a$1(this,"localAgentList",[]);a$1(this,"reconnectAttempts",0);a$1(this,"reconnectTimer",null);a$1(this,"heartbeatTimer",null);a$1(this,"agentListRequestId",null);a$1(this,"agentListRequestResolve",null);this.config={url:e.url,type:e.type,id:e.id??`client_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,reconnect:{enabled:e.reconnect?.enabled??true,maxAttempts:e.reconnect?.maxAttempts??5,delay:e.reconnect?.delay??3e3},heartbeat:{enabled:e.heartbeat?.enabled??true,interval:e.heartbeat?.interval??3e4}},this.log=b.create({service:`gateway:client:${this.config.id}`});}async connect(){if(this.state==="connected"||this.state==="connecting"){this.log.warn("already connected or connecting");return}return this.state="connecting",this.log.info("connecting to gateway",{url:this.config.url}),new Promise((e,t)=>{try{this.ws=new WebSocket(this.config.url),this.ws.onopen=()=>{this.state="connected",this.reconnectAttempts=0,this.log.info("connected to gateway"),this.config.heartbeat.enabled&&this.startHeartbeat(),this.resubscribeAll(),e();},this.ws.onmessage=n=>{this.handleMessage(n.data);},this.ws.onclose=n=>{this.handleClose(n.code,n.reason);},this.ws.onerror=n=>{this.log.error("WebSocket error",{error:String(n)}),this.state==="connecting"&&t(new Error("Connection failed"));};}catch(n){this.state="disconnected",t(n);}})}async disconnect(){this.state!=="disconnected"&&(this.log.info("disconnecting from gateway"),this.stopHeartbeat(),this.stopReconnect(),this.ws&&(this.ws.close(1e3,"Client disconnect"),this.ws=null),this.state="disconnected",this.log.info("disconnected from gateway"));}async subscribe(e,t){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"subscribe",sessionId:e,backendSessionId:t,clientId:this.config.id}),this.log.info("subscribed to session",{sessionId:e,backendSessionId:t});}async unsubscribe(e){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"unsubscribe",sessionId:e,clientId:this.config.id}),this.subscriptions.delete(e),this.log.info("unsubscribed from session",{sessionId:e});}async send(e){if(this.state!=="connected")throw new Error("Not connected to gateway");this.sendData({type:"message",message:e});}onMessage(e){this.messageCallbacks.add(e);}offMessage(e){this.messageCallbacks.delete(e);}getState(){return this.state}getId(){return this.config.id}getSubscriptions(){return [...this.subscriptions.keys()]}setLocalAgents(e){this.localAgentList=e,this.updateMergedAgentList();}async fetchAgentList(){if(this.state!=="connected")throw new Error("Not connected to gateway");return new Promise((e,t)=>{let n=`req_${Date.now()}_${Math.random().toString(36).substring(2,9)}`;this.agentListRequestId=n,this.agentListRequestResolve=e,this.sendData({type:"agent_list_request",requestId:n}),setTimeout(()=>{this.agentListRequestId===n&&(this.agentListRequestId=null,this.agentListRequestResolve=null,t(new Error("Agent list request timeout")));},1e4);})}getConnectableAgents(e={}){let{localAgents:t,preferLocal:n=true,filterOffline:s=true}=e,r=t||this.localAgentList,i=this.cachedAgentList,o=this.mergeAgentLists(r,i,n);return s?o.filter(p=>p.status!=="offline"):o}onAgentListChange(e){this.agentListCallbacks.add(e);}offAgentListChange(e){this.agentListCallbacks.delete(e);}mergeAgentLists(e,t,n){let s=new Map,r=n?t:e,i=n?e:t;for(let o of r)s.set(o.id,o);for(let o of i)s.set(o.id,o);return Array.from(s.values())}updateMergedAgentList(){let e=this.getConnectableAgents({filterOffline:false});for(let t of this.agentListCallbacks)try{t(e);}catch(n){this.log.error("agent list callback error",{error:String(n)});}}handleAgentListResponse(e,t){t&&this.agentListRequestId===t&&this.agentListRequestResolve&&(this.agentListRequestId=null,this.agentListRequestResolve(e),this.agentListRequestResolve=null),this.cachedAgentList=e,this.updateMergedAgentList(),this.log.debug("received agent list",{count:e.length});}sendData(e){if(!this.ws||this.ws.readyState!==WebSocket.OPEN){this.log.warn("WebSocket not ready, cannot send");return}this.ws.send(JSON.stringify(e));}handleMessage(e){try{let t=JSON.parse(e);switch(t.type){case "message":this.handleGatewayMessage(t.message);break;case "subscribed":this.subscriptions.set(t.sessionId,t.subscription);break;case "unsubscribed":this.subscriptions.delete(t.sessionId);break;case "pong":break;case "agent_list_response":this.handleAgentListResponse(t.agents||[],t.requestId);break;case "agent_update":this.handleAgentUpdate(t.agent,t.action);break;default:this.log.debug("unknown message type",{type:t.type});}}catch(t){this.log.error("failed to parse message",{error:String(t)});}}handleAgentUpdate(e,t){switch(t){case "add":case "update":{let n=this.cachedAgentList.findIndex(s=>s.id===e.id);n>=0?this.cachedAgentList[n]=e:this.cachedAgentList.push(e);break}case "remove":this.cachedAgentList=this.cachedAgentList.filter(n=>n.id!==e.id);break}this.updateMergedAgentList();}handleGatewayMessage(e){for(let t of this.messageCallbacks)try{t(e);}catch(n){this.log.error("message callback error",{error:String(n)});}}handleClose(e,t){this.log.info("connection closed",{code:e,reason:t}),this.state="disconnected",this.ws=null,this.stopHeartbeat(),this.config.reconnect.enabled&&this.scheduleReconnect();}scheduleReconnect(){if(this.reconnectAttempts>=this.config.reconnect.maxAttempts){this.log.error("max reconnect attempts reached");return}this.reconnectAttempts++,this.state="reconnecting";let e=this.config.reconnect.delay*this.reconnectAttempts;this.log.info("scheduling reconnect",{attempt:this.reconnectAttempts,delay:e}),this.reconnectTimer=setTimeout(async()=>{try{await this.connect();}catch(t){this.log.error("reconnect failed",{error:String(t)});}},e);}stopReconnect(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{this.state==="connected"&&this.sendData({type:"ping"});},this.config.heartbeat.interval);}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null);}async resubscribeAll(){for(let e of this.subscriptions.keys())try{await this.subscribe(e);}catch(t){this.log.error("failed to resubscribe",{sessionId:e,error:String(t)});}}getHttpUrl(){return this.config.url.replace(/^ws:/,"http:").replace(/^wss:/,"https:").replace(/\/$/,"")}async httpRequest(e,t={}){let n=`${this.getHttpUrl()}${e}`,s=t.method||"GET",{signal:r,...i}=t,o=await Fetch.request(n,{method:s,...i,headers:{"Content-Type":"application/json",...i.headers},...r?{signal:r}:{}});if(!o.ok){let p=o.data,G=typeof p=="object"?JSON.stringify(p):String(p||"Unknown error");throw new Error(`HTTP ${o.status}: ${G}`)}return o.data}async healthCheck(){return this.httpRequest("/health")}async getStatus(){return this.httpRequest("/status")}async listChannels(){return this.httpRequest("/channels")}async listContacts(e,t={}){let n=new URLSearchParams({platform:e,limit:String(t.limit??100),offset:String(t.offset??0)});return this.httpRequest(`/contacts?${n}`)}async getContact(e){return this.httpRequest(`/contacts/${encodeURIComponent(e)}`)}async getSession(e){return this.httpRequest(`/sessions/${encodeURIComponent(e)}`)}async createSession(e){return this.httpRequest("/session",{method:"POST",body:JSON.stringify(e??{})})}async getOrCreateSession(e){if(e.sessionId)try{return await this.getSession(e.sessionId),{sessionId:e.sessionId,created:!1}}catch{this.log.debug("session not found, will create new",{sessionId:e.sessionId});}if(e.platform||e.channel||e.userId){let n=e.chatId??e.userId;try{let i=await this.listSessions({platform:e.platform,channelId:e.channel,userId:e.userId,chatId:n});if(i.sessions.length>0){let o=i.sessions[0];if(o)return this.log.info("found existing session",{sessionId:o.id,channel:e.channel,userId:e.userId,chatId:n}),{sessionId:o.id,created:!1}}}catch(i){this.log.warn("failed to search sessions",{error:String(i)});}let s={channel:{platform:e.platform,channelId:e.channel,userId:e.userId,chatId:n}},r=await this.createSession(s);return this.log.info("session created",{sessionId:r.id,params:s}),{sessionId:r.id,created:true}}let t=await this.createSession({channel:{platform:"api",channelId:"default"}});return this.log.info("session created (default)",{sessionId:t.id}),{sessionId:t.id,created:true}}async listSessions(e={}){let t=new URLSearchParams;return t.set("limit",String(e.limit??100)),t.set("offset",String(e.offset??0)),e.platform&&t.set("platform",e.platform),e.channelId&&t.set("channelId",e.channelId),e.userId&&t.set("userId",e.userId),e.chatId&&t.set("chatId",e.chatId),this.httpRequest(`/sessions?${t}`)}async sendMessage(e,t){return this.httpRequest(`/session/${encodeURIComponent(e)}/prompt`,{method:"POST",body:JSON.stringify(t)})}};async function Jt(c){let{Log:e}=await import('./chunks/log-FQII2FT4.mjs'),t=false;await e.init({logDir:c.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:c.print??false,dev:c.dev??t,level:c.level??("INFO")});}
|
|
2
|
+
export{T as AgentRegistry,M as AgentSyncManager,x as Gateway,N as GatewayClient,Jt as initLog};
|