ai-consultation-mcp 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.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -0
  3. package/dist/api/index.d.ts +27 -0
  4. package/dist/api/index.js +213 -0
  5. package/dist/api/index.js.map +1 -0
  6. package/dist/api/middleware/security.d.ts +6 -0
  7. package/dist/api/middleware/security.js +28 -0
  8. package/dist/api/middleware/security.js.map +1 -0
  9. package/dist/api/routes/chat.d.ts +2 -0
  10. package/dist/api/routes/chat.js +78 -0
  11. package/dist/api/routes/chat.js.map +1 -0
  12. package/dist/api/routes/config.d.ts +2 -0
  13. package/dist/api/routes/config.js +81 -0
  14. package/dist/api/routes/config.js.map +1 -0
  15. package/dist/api/routes/providers.d.ts +2 -0
  16. package/dist/api/routes/providers.js +225 -0
  17. package/dist/api/routes/providers.js.map +1 -0
  18. package/dist/api/standalone-server.d.ts +12 -0
  19. package/dist/api/standalone-server.js +117 -0
  20. package/dist/api/standalone-server.js.map +1 -0
  21. package/dist/config/defaults.d.ts +17 -0
  22. package/dist/config/defaults.js +30 -0
  23. package/dist/config/defaults.js.map +1 -0
  24. package/dist/config/encryption.d.ts +12 -0
  25. package/dist/config/encryption.js +85 -0
  26. package/dist/config/encryption.js.map +1 -0
  27. package/dist/config/index.d.ts +5 -0
  28. package/dist/config/index.js +6 -0
  29. package/dist/config/index.js.map +1 -0
  30. package/dist/config/manager.d.ts +62 -0
  31. package/dist/config/manager.js +210 -0
  32. package/dist/config/manager.js.map +1 -0
  33. package/dist/config/prompts.d.ts +10 -0
  34. package/dist/config/prompts.js +168 -0
  35. package/dist/config/prompts.js.map +1 -0
  36. package/dist/config/schema.d.ts +141 -0
  37. package/dist/config/schema.js +54 -0
  38. package/dist/config/schema.js.map +1 -0
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.js +260 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/installer/detector.d.ts +48 -0
  43. package/dist/installer/detector.js +164 -0
  44. package/dist/installer/detector.js.map +1 -0
  45. package/dist/installer/index.d.ts +7 -0
  46. package/dist/installer/index.js +10 -0
  47. package/dist/installer/index.js.map +1 -0
  48. package/dist/installer/installer.d.ts +16 -0
  49. package/dist/installer/installer.js +262 -0
  50. package/dist/installer/installer.js.map +1 -0
  51. package/dist/installer/tools.d.ts +16 -0
  52. package/dist/installer/tools.js +327 -0
  53. package/dist/installer/tools.js.map +1 -0
  54. package/dist/installer/types.d.ts +68 -0
  55. package/dist/installer/types.js +5 -0
  56. package/dist/installer/types.js.map +1 -0
  57. package/dist/providers/base.d.ts +44 -0
  58. package/dist/providers/base.js +84 -0
  59. package/dist/providers/base.js.map +1 -0
  60. package/dist/providers/deepseek.d.ts +30 -0
  61. package/dist/providers/deepseek.js +148 -0
  62. package/dist/providers/deepseek.js.map +1 -0
  63. package/dist/providers/index.d.ts +5 -0
  64. package/dist/providers/index.js +8 -0
  65. package/dist/providers/index.js.map +1 -0
  66. package/dist/providers/openai.d.ts +30 -0
  67. package/dist/providers/openai.js +123 -0
  68. package/dist/providers/openai.js.map +1 -0
  69. package/dist/providers/registry.d.ts +37 -0
  70. package/dist/providers/registry.js +65 -0
  71. package/dist/providers/registry.js.map +1 -0
  72. package/dist/providers/types.d.ts +71 -0
  73. package/dist/providers/types.js +2 -0
  74. package/dist/providers/types.js.map +1 -0
  75. package/dist/server/conversation.d.ts +105 -0
  76. package/dist/server/conversation.js +279 -0
  77. package/dist/server/conversation.js.map +1 -0
  78. package/dist/server/index.d.ts +2 -0
  79. package/dist/server/index.js +3 -0
  80. package/dist/server/index.js.map +1 -0
  81. package/dist/server/tools/consult.d.ts +15 -0
  82. package/dist/server/tools/consult.js +164 -0
  83. package/dist/server/tools/consult.js.map +1 -0
  84. package/dist/server/tools/index.d.ts +1 -0
  85. package/dist/server/tools/index.js +2 -0
  86. package/dist/server/tools/index.js.map +1 -0
  87. package/dist/types/config.d.ts +20 -0
  88. package/dist/types/config.js +2 -0
  89. package/dist/types/config.js.map +1 -0
  90. package/dist/types/index.d.ts +3 -0
  91. package/dist/types/index.js +4 -0
  92. package/dist/types/index.js.map +1 -0
  93. package/dist/types/messages.d.ts +48 -0
  94. package/dist/types/messages.js +2 -0
  95. package/dist/types/messages.js.map +1 -0
  96. package/dist/types/models.d.ts +39 -0
  97. package/dist/types/models.js +66 -0
  98. package/dist/types/models.js.map +1 -0
  99. package/dist/ui/index.html +1244 -0
  100. package/dist/utils/errors.d.ts +32 -0
  101. package/dist/utils/errors.js +53 -0
  102. package/dist/utils/errors.js.map +1 -0
  103. package/dist/utils/index.d.ts +2 -0
  104. package/dist/utils/index.js +3 -0
  105. package/dist/utils/index.js.map +1 -0
  106. package/dist/utils/logger.d.ts +13 -0
  107. package/dist/utils/logger.js +73 -0
  108. package/dist/utils/logger.js.map +1 -0
  109. package/package.json +65 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Registry for managing provider instances
3
+ */
4
+ export class ProviderRegistry {
5
+ providers = new Map();
6
+ /**
7
+ * Register a provider
8
+ */
9
+ register(provider) {
10
+ this.providers.set(provider.name, provider);
11
+ }
12
+ /**
13
+ * Get a provider by name
14
+ */
15
+ getProvider(name) {
16
+ const provider = this.providers.get(name);
17
+ if (!provider) {
18
+ throw new Error(`Provider not found: ${name}`);
19
+ }
20
+ return provider;
21
+ }
22
+ /**
23
+ * Check if a provider exists
24
+ */
25
+ hasProvider(name) {
26
+ return this.providers.has(name);
27
+ }
28
+ /**
29
+ * Get all registered providers
30
+ */
31
+ getAllProviders() {
32
+ return Array.from(this.providers.values());
33
+ }
34
+ /**
35
+ * Get all configured providers
36
+ */
37
+ getConfiguredProviders() {
38
+ return this.getAllProviders().filter((p) => p.isConfigured());
39
+ }
40
+ }
41
+ // Singleton instance
42
+ let registryInstance = null;
43
+ /**
44
+ * Get the provider registry instance
45
+ */
46
+ export function getProviderRegistry() {
47
+ if (!registryInstance) {
48
+ registryInstance = new ProviderRegistry();
49
+ }
50
+ return registryInstance;
51
+ }
52
+ /**
53
+ * Initialize the registry with all providers
54
+ * Called during server startup
55
+ */
56
+ export async function initializeProviders() {
57
+ const registry = getProviderRegistry();
58
+ // Import providers dynamically to avoid circular dependencies
59
+ const { DeepSeekProvider } = await import('./deepseek.js');
60
+ const { OpenAIProvider } = await import('./openai.js');
61
+ // Register providers
62
+ registry.register(new DeepSeekProvider());
63
+ registry.register(new OpenAIProvider());
64
+ }
65
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACnB,SAAS,GAAiC,IAAI,GAAG,EAAE,CAAC;IAE5D;;OAEG;IACH,QAAQ,CAAC,QAAmB;QAC1B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,IAAkB;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,IAAkB;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,sBAAsB;QACpB,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;IAChE,CAAC;CACF;AAED,qBAAqB;AACrB,IAAI,gBAAgB,GAA4B,IAAI,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,QAAQ,GAAG,mBAAmB,EAAE,CAAC;IAEvC,8DAA8D;IAC9D,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IAC3D,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAEvD,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { ModelType, ProviderType } from '../types/index.js';
2
+ /**
3
+ * Message format for provider communication
4
+ */
5
+ export interface ProviderMessage {
6
+ role: 'user' | 'assistant' | 'system';
7
+ content: string;
8
+ }
9
+ /**
10
+ * Options for creating a completion
11
+ */
12
+ export interface CompletionOptions {
13
+ model: ModelType;
14
+ systemPrompt?: string;
15
+ maxTokens?: number;
16
+ temperature?: number;
17
+ }
18
+ /**
19
+ * Token usage information
20
+ */
21
+ export interface TokenUsage {
22
+ promptTokens: number;
23
+ completionTokens: number;
24
+ totalTokens: number;
25
+ }
26
+ /**
27
+ * Response from a provider
28
+ */
29
+ export interface ProviderResponse {
30
+ content: string;
31
+ model: string;
32
+ usage?: TokenUsage;
33
+ finishReason?: string;
34
+ reasoningContent?: string;
35
+ responseTime?: number;
36
+ }
37
+ /**
38
+ * Provider error information
39
+ */
40
+ export interface ProviderErrorInfo {
41
+ provider: ProviderType;
42
+ code: string;
43
+ message: string;
44
+ retryable: boolean;
45
+ statusCode?: number;
46
+ }
47
+ /**
48
+ * Provider interface - all providers must implement this
49
+ */
50
+ export interface IProvider {
51
+ readonly name: ProviderType;
52
+ /**
53
+ * Check if the provider is configured with valid credentials
54
+ */
55
+ isConfigured(): boolean;
56
+ /**
57
+ * Create a chat completion
58
+ */
59
+ createCompletion(messages: ProviderMessage[], options: CompletionOptions): Promise<ProviderResponse>;
60
+ }
61
+ /**
62
+ * Model configuration
63
+ */
64
+ export interface ModelConfig {
65
+ provider: ProviderType;
66
+ apiModel: string;
67
+ maxTokens: number;
68
+ supportsSystemPrompt: boolean;
69
+ isReasoning: boolean;
70
+ reasoningEffort?: 'low' | 'medium' | 'high';
71
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,105 @@
1
+ import type { Message, ModelType } from '../types/index.js';
2
+ /**
3
+ * Serializable conversation for file storage
4
+ */
5
+ interface SerializedConversation {
6
+ id: string;
7
+ model: ModelType;
8
+ messages: Message[];
9
+ systemPrompt: string;
10
+ createdAt: string;
11
+ lastActivityAt: string;
12
+ }
13
+ /**
14
+ * Archived conversation with end reason
15
+ */
16
+ export interface ArchivedConversation extends SerializedConversation {
17
+ endedAt: string;
18
+ endReason: 'completed' | 'timeout' | 'manual' | 'session_restart';
19
+ }
20
+ /**
21
+ * Represents an active conversation
22
+ */
23
+ export interface Conversation {
24
+ id: string;
25
+ model: ModelType;
26
+ messages: Message[];
27
+ systemPrompt: string;
28
+ createdAt: Date;
29
+ lastActivityAt: Date;
30
+ }
31
+ /**
32
+ * Manages active conversations with file persistence
33
+ *
34
+ * Note: Multiple MCP instances may run concurrently (different agents).
35
+ * Each instance only tracks its own conversations in memory.
36
+ * File storage is append-only for history - we don't clear other instances' data.
37
+ */
38
+ export declare class ConversationManager {
39
+ private conversations;
40
+ private cleanupInterval;
41
+ constructor();
42
+ /**
43
+ * Load existing active conversations from file
44
+ * This allows the Web UI to see conversations from all instances
45
+ */
46
+ private loadExistingConversations;
47
+ /**
48
+ * Save conversations to file
49
+ */
50
+ private saveToFile;
51
+ /**
52
+ * Load conversations from file (static method for external use)
53
+ */
54
+ static loadFromFile(): Conversation[];
55
+ /**
56
+ * Load archived conversations from history file (static method for external use)
57
+ */
58
+ static loadHistoryFromFile(): ArchivedConversation[];
59
+ /**
60
+ * Archive a conversation to history file
61
+ */
62
+ private archiveConversation;
63
+ /**
64
+ * Create a new conversation
65
+ */
66
+ create(model: ModelType, systemPrompt: string): Conversation;
67
+ /**
68
+ * Get a conversation by ID
69
+ */
70
+ get(conversationId: string): Conversation;
71
+ /**
72
+ * Add a message to a conversation
73
+ */
74
+ addMessage(conversationId: string, role: Message['role'], content: string): void;
75
+ /**
76
+ * Check if conversation can continue
77
+ */
78
+ canContinue(conversationId: string): boolean;
79
+ /**
80
+ * Get message count for a conversation
81
+ */
82
+ getMessageCount(conversationId: string): number;
83
+ /**
84
+ * End a conversation (archives it to history)
85
+ */
86
+ end(conversationId: string): number;
87
+ /**
88
+ * List all active conversations
89
+ */
90
+ listActive(): Conversation[];
91
+ /**
92
+ * Start periodic cleanup of stale conversations
93
+ */
94
+ private startCleanup;
95
+ /**
96
+ * Clean up stale conversations (archives them to history)
97
+ */
98
+ private cleanupStale;
99
+ /**
100
+ * Stop the cleanup interval
101
+ */
102
+ destroy(): void;
103
+ }
104
+ export declare const conversationManager: ConversationManager;
105
+ export {};
@@ -0,0 +1,279 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { ConversationError } from '../utils/index.js';
6
+ import { MAX_MESSAGES_LIMIT, CONVERSATION_TIMEOUT_MS } from '../config/index.js';
7
+ // Config directory in user's home (consistent across all invocations)
8
+ const CONFIG_DIR = path.join(os.homedir(), '.ai-consultation-mcp');
9
+ // Ensure config directory exists
10
+ if (!fs.existsSync(CONFIG_DIR)) {
11
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
12
+ }
13
+ // Conversations file paths (in home directory)
14
+ const CONVERSATIONS_FILE = path.join(CONFIG_DIR, 'conversations.json');
15
+ const HISTORY_FILE = path.join(CONFIG_DIR, 'conversation_history.json');
16
+ /**
17
+ * Manages active conversations with file persistence
18
+ *
19
+ * Note: Multiple MCP instances may run concurrently (different agents).
20
+ * Each instance only tracks its own conversations in memory.
21
+ * File storage is append-only for history - we don't clear other instances' data.
22
+ */
23
+ export class ConversationManager {
24
+ conversations = new Map();
25
+ cleanupInterval = null;
26
+ constructor() {
27
+ // Load any existing conversations from file into memory
28
+ this.loadExistingConversations();
29
+ // Start cleanup interval for timeout handling
30
+ this.startCleanup();
31
+ }
32
+ /**
33
+ * Load existing active conversations from file
34
+ * This allows the Web UI to see conversations from all instances
35
+ */
36
+ loadExistingConversations() {
37
+ try {
38
+ if (!fs.existsSync(CONVERSATIONS_FILE)) {
39
+ return;
40
+ }
41
+ const data = fs.readFileSync(CONVERSATIONS_FILE, 'utf-8');
42
+ const serialized = JSON.parse(data);
43
+ // Load into memory map
44
+ for (const conv of serialized) {
45
+ const conversation = {
46
+ id: conv.id,
47
+ model: conv.model,
48
+ messages: conv.messages,
49
+ systemPrompt: conv.systemPrompt,
50
+ createdAt: new Date(conv.createdAt),
51
+ lastActivityAt: new Date(conv.lastActivityAt),
52
+ };
53
+ this.conversations.set(conversation.id, conversation);
54
+ }
55
+ if (serialized.length > 0) {
56
+ console.log(`[ConversationManager] Loaded ${serialized.length} existing conversations`);
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.error('[ConversationManager] Failed to load existing conversations:', error);
61
+ }
62
+ }
63
+ /**
64
+ * Save conversations to file
65
+ */
66
+ saveToFile() {
67
+ try {
68
+ const data = Array.from(this.conversations.values()).map(conv => ({
69
+ id: conv.id,
70
+ model: conv.model,
71
+ messages: conv.messages,
72
+ systemPrompt: conv.systemPrompt,
73
+ createdAt: conv.createdAt.toISOString(),
74
+ lastActivityAt: conv.lastActivityAt.toISOString(),
75
+ }));
76
+ // Ensure config directory exists
77
+ const configDir = path.dirname(CONVERSATIONS_FILE);
78
+ if (!fs.existsSync(configDir)) {
79
+ fs.mkdirSync(configDir, { recursive: true });
80
+ }
81
+ fs.writeFileSync(CONVERSATIONS_FILE, JSON.stringify(data, null, 2), 'utf-8');
82
+ }
83
+ catch (error) {
84
+ console.error('Failed to save conversations:', error);
85
+ }
86
+ }
87
+ /**
88
+ * Load conversations from file (static method for external use)
89
+ */
90
+ static loadFromFile() {
91
+ try {
92
+ if (!fs.existsSync(CONVERSATIONS_FILE)) {
93
+ return [];
94
+ }
95
+ const data = fs.readFileSync(CONVERSATIONS_FILE, 'utf-8');
96
+ const serialized = JSON.parse(data);
97
+ return serialized.map(conv => ({
98
+ id: conv.id,
99
+ model: conv.model,
100
+ messages: conv.messages,
101
+ systemPrompt: conv.systemPrompt,
102
+ createdAt: new Date(conv.createdAt),
103
+ lastActivityAt: new Date(conv.lastActivityAt),
104
+ }));
105
+ }
106
+ catch (error) {
107
+ console.error('Failed to load conversations:', error);
108
+ return [];
109
+ }
110
+ }
111
+ /**
112
+ * Load archived conversations from history file (static method for external use)
113
+ */
114
+ static loadHistoryFromFile() {
115
+ try {
116
+ if (!fs.existsSync(HISTORY_FILE)) {
117
+ return [];
118
+ }
119
+ const data = fs.readFileSync(HISTORY_FILE, 'utf-8');
120
+ return JSON.parse(data);
121
+ }
122
+ catch (error) {
123
+ console.error('Failed to load conversation history:', error);
124
+ return [];
125
+ }
126
+ }
127
+ /**
128
+ * Archive a conversation to history file
129
+ */
130
+ archiveConversation(conversation, reason) {
131
+ try {
132
+ // Load existing history
133
+ let history = [];
134
+ if (fs.existsSync(HISTORY_FILE)) {
135
+ const data = fs.readFileSync(HISTORY_FILE, 'utf-8');
136
+ history = JSON.parse(data);
137
+ }
138
+ // Add archived conversation
139
+ const archived = {
140
+ id: conversation.id,
141
+ model: conversation.model,
142
+ messages: conversation.messages,
143
+ systemPrompt: conversation.systemPrompt,
144
+ createdAt: conversation.createdAt.toISOString(),
145
+ lastActivityAt: conversation.lastActivityAt.toISOString(),
146
+ endedAt: new Date().toISOString(),
147
+ endReason: reason,
148
+ };
149
+ history.unshift(archived); // Add to beginning (newest first)
150
+ // Keep only last 100 conversations
151
+ if (history.length > 100) {
152
+ history = history.slice(0, 100);
153
+ }
154
+ // Ensure config directory exists
155
+ const configDir = path.dirname(HISTORY_FILE);
156
+ if (!fs.existsSync(configDir)) {
157
+ fs.mkdirSync(configDir, { recursive: true });
158
+ }
159
+ fs.writeFileSync(HISTORY_FILE, JSON.stringify(history, null, 2), 'utf-8');
160
+ }
161
+ catch (error) {
162
+ console.error('Failed to archive conversation:', error);
163
+ }
164
+ }
165
+ /**
166
+ * Create a new conversation
167
+ */
168
+ create(model, systemPrompt) {
169
+ const conversation = {
170
+ id: uuidv4(),
171
+ model,
172
+ messages: [],
173
+ systemPrompt,
174
+ createdAt: new Date(),
175
+ lastActivityAt: new Date(),
176
+ };
177
+ this.conversations.set(conversation.id, conversation);
178
+ this.saveToFile();
179
+ return conversation;
180
+ }
181
+ /**
182
+ * Get a conversation by ID
183
+ */
184
+ get(conversationId) {
185
+ const conversation = this.conversations.get(conversationId);
186
+ if (!conversation) {
187
+ throw new ConversationError(`Conversation not found: ${conversationId}`, conversationId);
188
+ }
189
+ return conversation;
190
+ }
191
+ /**
192
+ * Add a message to a conversation
193
+ */
194
+ addMessage(conversationId, role, content) {
195
+ const conversation = this.get(conversationId);
196
+ // Check message limit
197
+ if (conversation.messages.length >= MAX_MESSAGES_LIMIT * 2) {
198
+ throw new ConversationError(`Maximum message limit (${MAX_MESSAGES_LIMIT} exchanges) reached`, conversationId);
199
+ }
200
+ conversation.messages.push({ role, content });
201
+ conversation.lastActivityAt = new Date();
202
+ this.saveToFile();
203
+ }
204
+ /**
205
+ * Check if conversation can continue
206
+ */
207
+ canContinue(conversationId) {
208
+ const conversation = this.get(conversationId);
209
+ // Each exchange = 1 user + 1 assistant message = 2 messages
210
+ // maxMessages represents exchanges, so multiply by 2
211
+ return conversation.messages.length < MAX_MESSAGES_LIMIT * 2;
212
+ }
213
+ /**
214
+ * Get message count for a conversation
215
+ */
216
+ getMessageCount(conversationId) {
217
+ const conversation = this.get(conversationId);
218
+ return conversation.messages.length;
219
+ }
220
+ /**
221
+ * End a conversation (archives it to history)
222
+ */
223
+ end(conversationId) {
224
+ const conversation = this.get(conversationId);
225
+ const totalMessages = conversation.messages.length;
226
+ // Archive before deleting
227
+ this.archiveConversation(conversation, 'completed');
228
+ this.conversations.delete(conversationId);
229
+ this.saveToFile();
230
+ return totalMessages;
231
+ }
232
+ /**
233
+ * List all active conversations
234
+ */
235
+ listActive() {
236
+ return Array.from(this.conversations.values());
237
+ }
238
+ /**
239
+ * Start periodic cleanup of stale conversations
240
+ */
241
+ startCleanup() {
242
+ this.cleanupInterval = setInterval(() => {
243
+ this.cleanupStale();
244
+ }, 60000); // Check every minute
245
+ }
246
+ /**
247
+ * Clean up stale conversations (archives them to history)
248
+ */
249
+ cleanupStale() {
250
+ const now = Date.now();
251
+ let changed = false;
252
+ for (const [id, conversation] of this.conversations) {
253
+ const age = now - conversation.lastActivityAt.getTime();
254
+ if (age > CONVERSATION_TIMEOUT_MS) {
255
+ // Archive before deleting
256
+ this.archiveConversation(conversation, 'timeout');
257
+ this.conversations.delete(id);
258
+ changed = true;
259
+ }
260
+ }
261
+ if (changed) {
262
+ this.saveToFile();
263
+ }
264
+ }
265
+ /**
266
+ * Stop the cleanup interval
267
+ */
268
+ destroy() {
269
+ if (this.cleanupInterval) {
270
+ clearInterval(this.cleanupInterval);
271
+ this.cleanupInterval = null;
272
+ }
273
+ this.conversations.clear();
274
+ this.saveToFile();
275
+ }
276
+ }
277
+ // Singleton instance
278
+ export const conversationManager = new ConversationManager();
279
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/server/conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { conversationManager } from './conversation.js';
2
+ export * from './tools/index.js';
@@ -0,0 +1,3 @@
1
+ export { conversationManager } from './conversation.js';
2
+ export * from './tools/index.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { z } from 'zod';
2
+ import { consultRequestSchema, continueRequestSchema, endRequestSchema } from '../../config/schema.js';
3
+ import type { ConsultResponse, ContinueResponse, EndResponse } from '../../types/index.js';
4
+ /**
5
+ * Consult an AI agent for a second opinion
6
+ */
7
+ export declare function consultAgent(input: z.infer<typeof consultRequestSchema>): Promise<ConsultResponse>;
8
+ /**
9
+ * Continue an existing conversation
10
+ */
11
+ export declare function continueConversation(input: z.infer<typeof continueRequestSchema>): Promise<ContinueResponse>;
12
+ /**
13
+ * End a conversation
14
+ */
15
+ export declare function endConversation(input: z.infer<typeof endRequestSchema>): Promise<EndResponse>;