@probelabs/probe-chat 0.6.0-rc197 → 0.6.0-rc199
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/ChatSessionManager.js +6 -3
- package/index.js +3 -12
- package/package.json +1 -1
- package/test/unit/chatSessionManager.test.js +86 -0
- package/webServer.js +14 -28
package/ChatSessionManager.js
CHANGED
|
@@ -63,15 +63,18 @@ export class ChatSessionManager {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
* Initialize the ChatSessionManager by loading history
|
|
66
|
+
* Initialize the ChatSessionManager by initializing ProbeAgent and loading history
|
|
67
67
|
* This must be called before using chat()
|
|
68
68
|
*/
|
|
69
69
|
async initialize() {
|
|
70
70
|
if (this._ready) return; // Already initialized
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
// Initialize ProbeAgent (handles API key detection and CLI fallback)
|
|
73
|
+
await this.agent.initialize();
|
|
74
|
+
|
|
72
75
|
await this.loadHistory();
|
|
73
76
|
this._ready = true;
|
|
74
|
-
|
|
77
|
+
|
|
75
78
|
if (this.debug) {
|
|
76
79
|
console.log(`[ChatSessionManager] Initialized session ${this.sessionId} with ${this.agent.history.length} messages from storage`);
|
|
77
80
|
}
|
package/index.js
CHANGED
|
@@ -346,12 +346,6 @@ export function main() {
|
|
|
346
346
|
process.env.PORT = options.port;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
// Check for API keys
|
|
350
|
-
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
351
|
-
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
352
|
-
const googleApiKey = process.env.GOOGLE_API_KEY;
|
|
353
|
-
const hasApiKeys = !!(anthropicApiKey || openaiApiKey || googleApiKey);
|
|
354
|
-
|
|
355
349
|
// --- Bash Configuration Processing ---
|
|
356
350
|
let bashConfig = null;
|
|
357
351
|
if (options.enableBash) {
|
|
@@ -406,16 +400,13 @@ export function main() {
|
|
|
406
400
|
|
|
407
401
|
// --- Web Mode (check before non-interactive to override) ---
|
|
408
402
|
if (options.web) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
logWarn(chalk.yellow('Warning: No API key provided. The web interface will show instructions on how to set up API keys.'));
|
|
412
|
-
}
|
|
413
|
-
// Import and start web server
|
|
403
|
+
// Note: API key / CLI availability is checked lazily in ProbeAgent.initialize()
|
|
404
|
+
// when the first chat message is sent. This allows fallback to Claude Code or Codex CLI.
|
|
414
405
|
import('./webServer.js')
|
|
415
406
|
.then(async module => {
|
|
416
407
|
const { startWebServer } = module;
|
|
417
408
|
logInfo(`Starting web server on port ${process.env.PORT || 8080}...`);
|
|
418
|
-
await startWebServer(version,
|
|
409
|
+
await startWebServer(version, { allowEdit: options.allowEdit });
|
|
419
410
|
})
|
|
420
411
|
.catch(error => {
|
|
421
412
|
logError(chalk.red(`Error starting web server: ${error.message}`));
|
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach, mock } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { ChatSessionManager } from '../../ChatSessionManager.js';
|
|
4
|
+
|
|
5
|
+
// Store original environment
|
|
6
|
+
let originalEnv;
|
|
7
|
+
|
|
8
|
+
describe('ChatSessionManager Tests', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Store original environment
|
|
11
|
+
originalEnv = { ...process.env };
|
|
12
|
+
|
|
13
|
+
// Set test mode
|
|
14
|
+
process.env.NODE_ENV = 'test';
|
|
15
|
+
process.env.USE_MOCK_AI = 'true';
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
// Restore original environment
|
|
20
|
+
Object.keys(process.env).forEach(key => {
|
|
21
|
+
if (!(key in originalEnv)) {
|
|
22
|
+
delete process.env[key];
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
Object.assign(process.env, originalEnv);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('initialize()', () => {
|
|
29
|
+
it('should call agent.initialize() when initializing', async () => {
|
|
30
|
+
// Create a ChatSessionManager
|
|
31
|
+
const session = new ChatSessionManager({
|
|
32
|
+
sessionId: 'test-session-123',
|
|
33
|
+
debug: false
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Track if agent.initialize was called
|
|
37
|
+
let agentInitializeCalled = false;
|
|
38
|
+
const originalInitialize = session.agent.initialize.bind(session.agent);
|
|
39
|
+
session.agent.initialize = async function() {
|
|
40
|
+
agentInitializeCalled = true;
|
|
41
|
+
return originalInitialize();
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Initialize the session
|
|
45
|
+
await session.initialize();
|
|
46
|
+
|
|
47
|
+
// Verify agent.initialize was called
|
|
48
|
+
assert.strictEqual(agentInitializeCalled, true, 'agent.initialize() should be called during ChatSessionManager.initialize()');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should only initialize once even if called multiple times', async () => {
|
|
52
|
+
const session = new ChatSessionManager({
|
|
53
|
+
sessionId: 'test-session-456',
|
|
54
|
+
debug: false
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let initializeCallCount = 0;
|
|
58
|
+
const originalInitialize = session.agent.initialize.bind(session.agent);
|
|
59
|
+
session.agent.initialize = async function() {
|
|
60
|
+
initializeCallCount++;
|
|
61
|
+
return originalInitialize();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Call initialize multiple times
|
|
65
|
+
await session.initialize();
|
|
66
|
+
await session.initialize();
|
|
67
|
+
await session.initialize();
|
|
68
|
+
|
|
69
|
+
// Should only be called once due to _ready flag
|
|
70
|
+
assert.strictEqual(initializeCallCount, 1, 'agent.initialize() should only be called once');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should set _ready flag after successful initialization', async () => {
|
|
74
|
+
const session = new ChatSessionManager({
|
|
75
|
+
sessionId: 'test-session-789',
|
|
76
|
+
debug: false
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
assert.strictEqual(session._ready, false, '_ready should be false before initialize');
|
|
80
|
+
|
|
81
|
+
await session.initialize();
|
|
82
|
+
|
|
83
|
+
assert.strictEqual(session._ready, true, '_ready should be true after initialize');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
package/webServer.js
CHANGED
|
@@ -98,13 +98,12 @@ function getOrCreateChat(sessionId, apiCredentials = null) {
|
|
|
98
98
|
/**
|
|
99
99
|
* Start the web server
|
|
100
100
|
* @param {string} version - The version of the application
|
|
101
|
-
* @param {boolean} hasApiKeys - Whether any API keys are configured
|
|
102
101
|
* @param {Object} options - Additional options
|
|
103
102
|
* @param {boolean} options.allowEdit - Whether to allow editing files via the implement tool
|
|
104
103
|
*/
|
|
105
|
-
export async function startWebServer(version,
|
|
104
|
+
export async function startWebServer(version, options = {}) {
|
|
106
105
|
const allowEdit = options?.allowEdit || false;
|
|
107
|
-
|
|
106
|
+
|
|
108
107
|
if (allowEdit) {
|
|
109
108
|
console.log('Edit mode enabled: implement tool is available');
|
|
110
109
|
}
|
|
@@ -120,11 +119,11 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
// Initialize persistent storage for web mode
|
|
123
|
-
globalStorage = new JsonChatStorage({
|
|
124
|
-
webMode: true,
|
|
125
|
-
verbose: process.env.DEBUG_CHAT === '1'
|
|
122
|
+
globalStorage = new JsonChatStorage({
|
|
123
|
+
webMode: true,
|
|
124
|
+
verbose: process.env.DEBUG_CHAT === '1'
|
|
126
125
|
});
|
|
127
|
-
|
|
126
|
+
|
|
128
127
|
// Initialize storage synchronously before server starts
|
|
129
128
|
try {
|
|
130
129
|
await globalStorage.initialize();
|
|
@@ -144,13 +143,9 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
144
143
|
? process.env.ALLOWED_FOLDERS.split(',').map(folder => folder.trim()).filter(Boolean)
|
|
145
144
|
: [];
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
console.log('Running in No API Keys mode - will show setup instructions to users');
|
|
151
|
-
} else {
|
|
152
|
-
console.log('API keys detected. Chat functionality enabled.');
|
|
153
|
-
}
|
|
146
|
+
// Note: API key / CLI availability is checked lazily in ProbeAgent.initialize()
|
|
147
|
+
// when the first chat message is sent. This allows fallback to Claude Code or Codex CLI.
|
|
148
|
+
console.log('Chat functionality enabled (API availability checked on first message)');
|
|
154
149
|
|
|
155
150
|
|
|
156
151
|
// Define the tools available for direct API calls (bypassing LLM loop)
|
|
@@ -419,7 +414,7 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
419
414
|
// UI Routes
|
|
420
415
|
'GET /': (req, res) => {
|
|
421
416
|
const htmlPath = join(__dirname, 'index.html');
|
|
422
|
-
serveHtml(res, htmlPath, { 'data-no-api-keys':
|
|
417
|
+
serveHtml(res, htmlPath, { 'data-no-api-keys': 'false' });
|
|
423
418
|
},
|
|
424
419
|
|
|
425
420
|
// Chat session route - serves HTML with injected session ID
|
|
@@ -428,15 +423,15 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
428
423
|
if (!sessionId) {
|
|
429
424
|
return sendError(res, 400, 'Invalid session ID in URL');
|
|
430
425
|
}
|
|
431
|
-
|
|
426
|
+
|
|
432
427
|
// Validate that session exists or at least has a valid UUID format
|
|
433
428
|
if (!isValidUUID(sessionId)) {
|
|
434
429
|
return sendError(res, 400, 'Invalid session ID format');
|
|
435
430
|
}
|
|
436
431
|
|
|
437
432
|
const htmlPath = join(__dirname, 'index.html');
|
|
438
|
-
serveHtml(res, htmlPath, {
|
|
439
|
-
'data-no-api-keys':
|
|
433
|
+
serveHtml(res, htmlPath, {
|
|
434
|
+
'data-no-api-keys': 'false',
|
|
440
435
|
'data-session-id': sessionId
|
|
441
436
|
});
|
|
442
437
|
},
|
|
@@ -451,7 +446,7 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
451
446
|
sendJson(res, 200, {
|
|
452
447
|
folders: folders,
|
|
453
448
|
currentDir: currentDir,
|
|
454
|
-
noApiKeysMode:
|
|
449
|
+
noApiKeysMode: false
|
|
455
450
|
});
|
|
456
451
|
},
|
|
457
452
|
|
|
@@ -700,12 +695,6 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
700
695
|
// Update last activity timestamp
|
|
701
696
|
chatInstance.lastActivity = Date.now();
|
|
702
697
|
|
|
703
|
-
// Check if API keys are needed but missing
|
|
704
|
-
if (chatInstance.noApiKeysMode) {
|
|
705
|
-
console.warn(`[WARN] Chat request for session ${chatSessionId} cannot proceed: No API keys configured.`);
|
|
706
|
-
return sendError(res, 503, 'Chat service unavailable: API key not configured on server.');
|
|
707
|
-
}
|
|
708
|
-
|
|
709
698
|
// Register this request as active for cancellation
|
|
710
699
|
registerRequest(chatSessionId, { abort: () => chatInstance.abort() });
|
|
711
700
|
if (DEBUG) console.log(`[DEBUG] Registered cancellable request for session: ${chatSessionId}`);
|
|
@@ -918,9 +907,6 @@ export async function startWebServer(version, hasApiKeys = true, options = {}) {
|
|
|
918
907
|
console.log(`Probe Web Interface v${version}`);
|
|
919
908
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
920
909
|
console.log(`Environment: ${process.env.NODE_ENV || 'development'}`);
|
|
921
|
-
if (noApiKeysMode) {
|
|
922
|
-
console.log('*** Running in NO API KEYS mode. Chat functionality disabled. ***');
|
|
923
|
-
}
|
|
924
910
|
});
|
|
925
911
|
}
|
|
926
912
|
|