@bernierllc/chat-suite 1.0.0
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/.eslintrc.js +26 -0
- package/README.md +542 -0
- package/__tests__/integration/ChatSuite.test.ts +235 -0
- package/__tests__/unit/ConfigManager.test.ts +122 -0
- package/__tests__/unit/MessageOrchestrator.test.ts +223 -0
- package/__tests__/unit/UserManager.test.ts +208 -0
- package/dist/ChatSuite.d.ts +76 -0
- package/dist/ChatSuite.d.ts.map +1 -0
- package/dist/ChatSuite.js +273 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/neverhub/discovery.d.ts +40 -0
- package/dist/neverhub/discovery.d.ts.map +1 -0
- package/dist/neverhub/discovery.js +106 -0
- package/dist/neverhub/event-handlers.d.ts +38 -0
- package/dist/neverhub/event-handlers.d.ts.map +1 -0
- package/dist/neverhub/event-handlers.js +125 -0
- package/dist/neverhub/index.d.ts +4 -0
- package/dist/neverhub/index.d.ts.map +1 -0
- package/dist/neverhub/index.js +26 -0
- package/dist/neverhub/service-registration.d.ts +29 -0
- package/dist/neverhub/service-registration.d.ts.map +1 -0
- package/dist/neverhub/service-registration.js +66 -0
- package/dist/providers/ChatKitProvider.d.ts +53 -0
- package/dist/providers/ChatKitProvider.d.ts.map +1 -0
- package/dist/providers/ChatKitProvider.js +167 -0
- package/dist/providers/ExternalProviders.d.ts +101 -0
- package/dist/providers/ExternalProviders.d.ts.map +1 -0
- package/dist/providers/ExternalProviders.js +153 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +25 -0
- package/dist/services/ConfigManager.d.ts +50 -0
- package/dist/services/ConfigManager.d.ts.map +1 -0
- package/dist/services/ConfigManager.js +95 -0
- package/dist/services/HealthMonitor.d.ts +58 -0
- package/dist/services/HealthMonitor.d.ts.map +1 -0
- package/dist/services/HealthMonitor.js +148 -0
- package/dist/services/MessageOrchestrator.d.ts +63 -0
- package/dist/services/MessageOrchestrator.d.ts.map +1 -0
- package/dist/services/MessageOrchestrator.js +212 -0
- package/dist/services/ProviderManager.d.ts +83 -0
- package/dist/services/ProviderManager.d.ts.map +1 -0
- package/dist/services/ProviderManager.js +204 -0
- package/dist/services/UserManager.d.ts +61 -0
- package/dist/services/UserManager.d.ts.map +1 -0
- package/dist/services/UserManager.js +141 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +28 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +26 -0
- package/dist/types/message-types.d.ts +80 -0
- package/dist/types/message-types.d.ts.map +1 -0
- package/dist/types/message-types.js +32 -0
- package/dist/types/provider-types.d.ts +96 -0
- package/dist/types/provider-types.d.ts.map +1 -0
- package/dist/types/provider-types.js +9 -0
- package/dist/types/suite-types.d.ts +101 -0
- package/dist/types/suite-types.d.ts.map +1 -0
- package/dist/types/suite-types.js +9 -0
- package/dist/utils/config-inheritance.d.ts +24 -0
- package/dist/utils/config-inheritance.d.ts.map +1 -0
- package/dist/utils/config-inheritance.js +167 -0
- package/dist/utils/error-handling.d.ts +37 -0
- package/dist/utils/error-handling.d.ts.map +1 -0
- package/dist/utils/error-handling.js +102 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +27 -0
- package/dist/utils/message-bridge.d.ts +68 -0
- package/dist/utils/message-bridge.d.ts.map +1 -0
- package/dist/utils/message-bridge.js +126 -0
- package/dist/utils/user-mapping.d.ts +63 -0
- package/dist/utils/user-mapping.d.ts.map +1 -0
- package/dist/utils/user-mapping.js +110 -0
- package/jest.config.cjs +30 -0
- package/package.json +67 -0
- package/src/ChatSuite.ts +347 -0
- package/src/index.ts +25 -0
- package/src/neverhub/discovery.ts +137 -0
- package/src/neverhub/event-handlers.ts +141 -0
- package/src/neverhub/index.ts +11 -0
- package/src/neverhub/service-registration.ts +89 -0
- package/src/providers/ChatKitProvider.ts +193 -0
- package/src/providers/ExternalProviders.ts +171 -0
- package/src/providers/index.ts +10 -0
- package/src/services/ConfigManager.ts +112 -0
- package/src/services/HealthMonitor.ts +169 -0
- package/src/services/MessageOrchestrator.ts +271 -0
- package/src/services/ProviderManager.ts +247 -0
- package/src/services/UserManager.ts +176 -0
- package/src/services/index.ts +13 -0
- package/src/types/index.ts +11 -0
- package/src/types/message-types.ts +94 -0
- package/src/types/provider-types.ts +116 -0
- package/src/types/suite-types.ts +117 -0
- package/src/utils/config-inheritance.ts +189 -0
- package/src/utils/error-handling.ts +114 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/message-bridge.ts +164 -0
- package/src/utils/user-mapping.ts +132 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
// @ts-nocheck
|
|
9
|
+
// TODO: Fix ServiceDiscoveryResult type compatibility
|
|
10
|
+
|
|
11
|
+
import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Discovered service information
|
|
15
|
+
*/
|
|
16
|
+
export interface DiscoveredService {
|
|
17
|
+
name: string;
|
|
18
|
+
type: string;
|
|
19
|
+
version: string;
|
|
20
|
+
capabilities: Array<{
|
|
21
|
+
type: string;
|
|
22
|
+
name: string;
|
|
23
|
+
version: string;
|
|
24
|
+
}>;
|
|
25
|
+
endpoint?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Discover chat providers through NeverHub
|
|
30
|
+
*/
|
|
31
|
+
export async function discoverProviders(
|
|
32
|
+
adapter: NeverHubAdapter
|
|
33
|
+
): Promise<DiscoveredService[]> {
|
|
34
|
+
try {
|
|
35
|
+
const services = await adapter.discover({
|
|
36
|
+
capabilityTypes: ['chat', 'chat-provider']
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(`✅ Discovered ${services.length} chat providers`);
|
|
40
|
+
return services;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('❌ Failed to discover providers:', error);
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Discover AI routing service
|
|
49
|
+
*/
|
|
50
|
+
export async function discoverAIRouter(
|
|
51
|
+
adapter: NeverHubAdapter
|
|
52
|
+
): Promise<DiscoveredService | undefined> {
|
|
53
|
+
try {
|
|
54
|
+
const services = await adapter.discover({
|
|
55
|
+
capabilityTypes: ['ai', 'routing']
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (services.length > 0) {
|
|
59
|
+
console.log(`✅ Discovered AI router: ${services[0].name}`);
|
|
60
|
+
return services[0];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log('⚠️ No AI router service found');
|
|
64
|
+
return undefined;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('❌ Failed to discover AI router:', error);
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Discover analytics service
|
|
73
|
+
*/
|
|
74
|
+
export async function discoverAnalytics(
|
|
75
|
+
adapter: NeverHubAdapter
|
|
76
|
+
): Promise<DiscoveredService | undefined> {
|
|
77
|
+
try {
|
|
78
|
+
const services = await adapter.discover({
|
|
79
|
+
capabilityTypes: ['analytics', 'chat-analytics']
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (services.length > 0) {
|
|
83
|
+
console.log(`✅ Discovered analytics service: ${services[0].name}`);
|
|
84
|
+
return services[0];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('⚠️ No analytics service found');
|
|
88
|
+
return undefined;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('❌ Failed to discover analytics:', error);
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Discover all chat-related services
|
|
97
|
+
*/
|
|
98
|
+
export async function discoverAllChatServices(
|
|
99
|
+
adapter: NeverHubAdapter
|
|
100
|
+
): Promise<{
|
|
101
|
+
providers: DiscoveredService[];
|
|
102
|
+
aiRouter?: DiscoveredService;
|
|
103
|
+
analytics?: DiscoveredService;
|
|
104
|
+
}> {
|
|
105
|
+
const [providers, aiRouter, analytics] = await Promise.all([
|
|
106
|
+
discoverProviders(adapter),
|
|
107
|
+
discoverAIRouter(adapter),
|
|
108
|
+
discoverAnalytics(adapter)
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
providers,
|
|
113
|
+
aiRouter,
|
|
114
|
+
analytics
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get service by name
|
|
120
|
+
*/
|
|
121
|
+
export async function getService(
|
|
122
|
+
adapter: NeverHubAdapter,
|
|
123
|
+
serviceName: string
|
|
124
|
+
): Promise<DiscoveredService | undefined> {
|
|
125
|
+
try {
|
|
126
|
+
const service = await adapter.getService(serviceName);
|
|
127
|
+
if (service) {
|
|
128
|
+
console.log(`✅ Found service: ${serviceName}`);
|
|
129
|
+
} else {
|
|
130
|
+
console.log(`⚠️ Service not found: ${serviceName}`);
|
|
131
|
+
}
|
|
132
|
+
return service;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(`❌ Failed to get service ${serviceName}:`, error);
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
// @ts-nocheck
|
|
9
|
+
// TODO: Fix NeverHubAdapter API compatibility
|
|
10
|
+
|
|
11
|
+
import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';
|
|
12
|
+
import type { MessageEvent, ProviderType } from '../types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* NeverHub event types for chat suite
|
|
16
|
+
*/
|
|
17
|
+
export enum ChatSuiteEventType {
|
|
18
|
+
MESSAGE_SENT = 'chat.message.sent',
|
|
19
|
+
MESSAGE_RECEIVED = 'chat.message.received',
|
|
20
|
+
MESSAGE_FAILED = 'chat.message.failed',
|
|
21
|
+
MESSAGE_BRIDGED = 'chat.message.bridged',
|
|
22
|
+
PROVIDER_INITIALIZED = 'chat.provider.initialized',
|
|
23
|
+
PROVIDER_FAILED = 'chat.provider.failed',
|
|
24
|
+
ROUTING_DECISION = 'chat.routing.decision'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Publish a message event to NeverHub
|
|
29
|
+
*/
|
|
30
|
+
export async function publishMessageEvent(
|
|
31
|
+
adapter: NeverHubAdapter,
|
|
32
|
+
event: MessageEvent
|
|
33
|
+
): Promise<boolean> {
|
|
34
|
+
try {
|
|
35
|
+
await adapter.publishEvent({
|
|
36
|
+
type: event.type,
|
|
37
|
+
data: {
|
|
38
|
+
messageId: event.messageId,
|
|
39
|
+
provider: event.provider,
|
|
40
|
+
timestamp: event.timestamp,
|
|
41
|
+
...event.data
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return true;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('❌ Failed to publish message event:', error);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Publish provider initialization event
|
|
53
|
+
*/
|
|
54
|
+
export async function publishProviderEvent(
|
|
55
|
+
adapter: NeverHubAdapter,
|
|
56
|
+
eventType: ChatSuiteEventType.PROVIDER_INITIALIZED | ChatSuiteEventType.PROVIDER_FAILED,
|
|
57
|
+
provider: ProviderType,
|
|
58
|
+
details?: Record<string, unknown>
|
|
59
|
+
): Promise<boolean> {
|
|
60
|
+
try {
|
|
61
|
+
await adapter.publishEvent({
|
|
62
|
+
type: eventType,
|
|
63
|
+
data: {
|
|
64
|
+
provider,
|
|
65
|
+
timestamp: new Date(),
|
|
66
|
+
...details
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return true;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error('❌ Failed to publish provider event:', error);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Publish routing decision event
|
|
78
|
+
*/
|
|
79
|
+
export async function publishRoutingEvent(
|
|
80
|
+
adapter: NeverHubAdapter,
|
|
81
|
+
messageId: string,
|
|
82
|
+
provider: ProviderType,
|
|
83
|
+
confidence: number,
|
|
84
|
+
reasoning?: string
|
|
85
|
+
): Promise<boolean> {
|
|
86
|
+
try {
|
|
87
|
+
await adapter.publishEvent({
|
|
88
|
+
type: ChatSuiteEventType.ROUTING_DECISION,
|
|
89
|
+
data: {
|
|
90
|
+
messageId,
|
|
91
|
+
provider,
|
|
92
|
+
confidence,
|
|
93
|
+
reasoning,
|
|
94
|
+
timestamp: new Date()
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return true;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('❌ Failed to publish routing event:', error);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Subscribe to chat events from NeverHub
|
|
106
|
+
*/
|
|
107
|
+
export async function subscribeToEvents(
|
|
108
|
+
adapter: NeverHubAdapter,
|
|
109
|
+
eventTypes: string[],
|
|
110
|
+
handler: (event: { type: string; data: Record<string, unknown> }) => void | Promise<void>
|
|
111
|
+
): Promise<boolean> {
|
|
112
|
+
try {
|
|
113
|
+
for (const eventType of eventTypes) {
|
|
114
|
+
await adapter.subscribe(eventType, handler);
|
|
115
|
+
}
|
|
116
|
+
console.log(`✅ Subscribed to ${eventTypes.length} event types`);
|
|
117
|
+
return true;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error('❌ Failed to subscribe to events:', error);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Unsubscribe from all events
|
|
126
|
+
*/
|
|
127
|
+
export async function unsubscribeFromEvents(
|
|
128
|
+
adapter: NeverHubAdapter,
|
|
129
|
+
eventTypes: string[]
|
|
130
|
+
): Promise<boolean> {
|
|
131
|
+
try {
|
|
132
|
+
for (const eventType of eventTypes) {
|
|
133
|
+
await adapter.unsubscribe(eventType);
|
|
134
|
+
}
|
|
135
|
+
console.log(`✅ Unsubscribed from ${eventTypes.length} event types`);
|
|
136
|
+
return true;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('❌ Failed to unsubscribe from events:', error);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './service-registration';
|
|
10
|
+
export * from './event-handlers';
|
|
11
|
+
export * from './discovery';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
// @ts-nocheck
|
|
9
|
+
// TODO: Fix NeverHubAdapter API compatibility
|
|
10
|
+
|
|
11
|
+
import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';
|
|
12
|
+
import type { NeverHubConfig } from '../types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Service registration data
|
|
16
|
+
*/
|
|
17
|
+
export interface ServiceRegistration {
|
|
18
|
+
type: string;
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
capabilities: Array<{
|
|
22
|
+
type: string;
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
}>;
|
|
26
|
+
dependencies: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Register chat suite with NeverHub
|
|
31
|
+
*/
|
|
32
|
+
export async function registerWithNeverHub(
|
|
33
|
+
adapter: NeverHubAdapter,
|
|
34
|
+
config: NeverHubConfig
|
|
35
|
+
): Promise<boolean> {
|
|
36
|
+
try {
|
|
37
|
+
const registration: ServiceRegistration = {
|
|
38
|
+
type: 'chat-suite',
|
|
39
|
+
name: config.serviceName,
|
|
40
|
+
version: '1.0.0',
|
|
41
|
+
capabilities: config.capabilities,
|
|
42
|
+
dependencies: config.dependencies
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
await adapter.register(registration);
|
|
46
|
+
console.log(`✅ Chat Suite registered with NeverHub: ${config.serviceName}`);
|
|
47
|
+
return true;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('❌ Failed to register with NeverHub:', error);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Unregister from NeverHub
|
|
56
|
+
*/
|
|
57
|
+
export async function unregisterFromNeverHub(
|
|
58
|
+
adapter: NeverHubAdapter
|
|
59
|
+
): Promise<boolean> {
|
|
60
|
+
try {
|
|
61
|
+
await adapter.unregister();
|
|
62
|
+
console.log('✅ Chat Suite unregistered from NeverHub');
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('❌ Failed to unregister from NeverHub:', error);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Update service health status in NeverHub
|
|
72
|
+
*/
|
|
73
|
+
export async function updateHealthStatus(
|
|
74
|
+
adapter: NeverHubAdapter,
|
|
75
|
+
status: 'healthy' | 'degraded' | 'unhealthy',
|
|
76
|
+
details?: Record<string, unknown>
|
|
77
|
+
): Promise<boolean> {
|
|
78
|
+
try {
|
|
79
|
+
await adapter.reportHealth({
|
|
80
|
+
status,
|
|
81
|
+
timestamp: new Date(),
|
|
82
|
+
details
|
|
83
|
+
});
|
|
84
|
+
return true;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('❌ Failed to update health status in NeverHub:', error);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
// @ts-nocheck
|
|
9
|
+
// TODO: Fix ChatKit API type compatibility
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
Provider,
|
|
13
|
+
ProviderMessage,
|
|
14
|
+
ProviderMessageResult,
|
|
15
|
+
ProviderHealth,
|
|
16
|
+
ProviderHealthStatus
|
|
17
|
+
} from '../types';
|
|
18
|
+
import { ChatKitAdapter } from '@bernierllc/chatkit-adapter';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* ChatKit provider configuration
|
|
22
|
+
*/
|
|
23
|
+
export interface ChatKitProviderConfig {
|
|
24
|
+
serviceName?: string;
|
|
25
|
+
features?: string[];
|
|
26
|
+
config?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ChatKit provider implementation
|
|
31
|
+
*/
|
|
32
|
+
export class ChatKitProvider implements Provider {
|
|
33
|
+
public readonly type = 'chatkit' as const;
|
|
34
|
+
public readonly name = '@bernierllc/chatkit-adapter';
|
|
35
|
+
|
|
36
|
+
private adapter?: ChatKitAdapter;
|
|
37
|
+
private initialized = false;
|
|
38
|
+
private errorCount = 0;
|
|
39
|
+
private lastError?: Error;
|
|
40
|
+
private initTime?: Date;
|
|
41
|
+
|
|
42
|
+
constructor(private config: ChatKitProviderConfig = {}) {}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Initialize the ChatKit provider
|
|
46
|
+
*/
|
|
47
|
+
public async initialize(): Promise<void> {
|
|
48
|
+
try {
|
|
49
|
+
this.adapter = new ChatKitAdapter({
|
|
50
|
+
apiKey: process.env.CHATKIT_API_KEY || 'demo-key',
|
|
51
|
+
...this.config.config
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.initialized = true;
|
|
55
|
+
this.initTime = new Date();
|
|
56
|
+
this.errorCount = 0;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
this.lastError = error instanceof Error ? error : new Error('Initialization failed');
|
|
59
|
+
this.errorCount++;
|
|
60
|
+
throw this.lastError;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if provider is initialized
|
|
66
|
+
*/
|
|
67
|
+
public isInitialized(): boolean {
|
|
68
|
+
return this.initialized && this.adapter !== undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Send a message through ChatKit
|
|
73
|
+
*/
|
|
74
|
+
public async sendMessage(message: ProviderMessage): Promise<ProviderMessageResult> {
|
|
75
|
+
if (!this.adapter) {
|
|
76
|
+
throw new Error('ChatKit adapter not initialized');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const result = await this.adapter.sendMessage({
|
|
81
|
+
content: message.content,
|
|
82
|
+
userId: message.userId,
|
|
83
|
+
channelId: message.channelId,
|
|
84
|
+
threadId: message.threadId,
|
|
85
|
+
attachments: message.attachments?.map(att => ({
|
|
86
|
+
filename: att.filename,
|
|
87
|
+
contentType: att.contentType,
|
|
88
|
+
data: att.data,
|
|
89
|
+
size: att.size
|
|
90
|
+
})),
|
|
91
|
+
metadata: message.metadata
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!result.success) {
|
|
95
|
+
this.errorCount++;
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error: result.error,
|
|
99
|
+
provider: 'chatkit'
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
messageId: result.messageId,
|
|
106
|
+
timestamp: result.timestamp ? new Date(result.timestamp) : new Date(),
|
|
107
|
+
provider: 'chatkit'
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
this.lastError = error instanceof Error ? error : new Error('Send message failed');
|
|
111
|
+
this.errorCount++;
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: this.lastError.message,
|
|
116
|
+
provider: 'chatkit'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get health status
|
|
123
|
+
*/
|
|
124
|
+
public async getHealth(): Promise<ProviderHealth> {
|
|
125
|
+
let status: ProviderHealthStatus = 'unknown';
|
|
126
|
+
let latency: number | undefined;
|
|
127
|
+
|
|
128
|
+
if (!this.initialized || !this.adapter) {
|
|
129
|
+
status = 'unhealthy';
|
|
130
|
+
} else {
|
|
131
|
+
const start = Date.now();
|
|
132
|
+
try {
|
|
133
|
+
// Simple health check - attempt to get adapter status
|
|
134
|
+
const isHealthy = this.adapter !== undefined;
|
|
135
|
+
latency = Date.now() - start;
|
|
136
|
+
|
|
137
|
+
if (isHealthy) {
|
|
138
|
+
if (this.errorCount === 0) {
|
|
139
|
+
status = 'healthy';
|
|
140
|
+
} else if (this.errorCount < 5) {
|
|
141
|
+
status = 'degraded';
|
|
142
|
+
} else {
|
|
143
|
+
status = 'unhealthy';
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
status = 'unhealthy';
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
latency = Date.now() - start;
|
|
150
|
+
status = 'unhealthy';
|
|
151
|
+
this.lastError = error instanceof Error ? error : new Error('Health check failed');
|
|
152
|
+
this.errorCount++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const uptime = this.initTime ? Date.now() - this.initTime.getTime() : undefined;
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
status,
|
|
160
|
+
lastCheck: new Date(),
|
|
161
|
+
latency,
|
|
162
|
+
errorCount: this.errorCount,
|
|
163
|
+
uptime,
|
|
164
|
+
details: {
|
|
165
|
+
lastError: this.lastError?.message,
|
|
166
|
+
features: this.config.features
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Shutdown the provider
|
|
173
|
+
*/
|
|
174
|
+
public async shutdown(): Promise<void> {
|
|
175
|
+
this.initialized = false;
|
|
176
|
+
this.adapter = undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get adapter instance (for advanced usage)
|
|
181
|
+
*/
|
|
182
|
+
public getAdapter(): ChatKitAdapter | undefined {
|
|
183
|
+
return this.adapter;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Reset error count
|
|
188
|
+
*/
|
|
189
|
+
public resetErrorCount(): void {
|
|
190
|
+
this.errorCount = 0;
|
|
191
|
+
this.lastError = undefined;
|
|
192
|
+
}
|
|
193
|
+
}
|