@probelabs/probe 0.6.0-rc167 → 0.6.0-rc168
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/build/agent/ProbeAgent.d.ts +7 -1
- package/build/agent/ProbeAgent.js +312 -15
- package/build/agent/engines/codex.js +347 -0
- package/build/agent/engines/enhanced-claude-code.js +3 -42
- package/build/agent/index.js +983 -59
- package/build/agent/mcp/built-in-server.js +334 -8
- package/build/agent/shared/Session.js +53 -0
- package/build/agent/shared/prompts.js +129 -0
- package/cjs/agent/ProbeAgent.cjs +986 -61
- package/cjs/index.cjs +995 -70
- package/index.d.ts +7 -1
- package/package.json +1 -1
- package/src/agent/ProbeAgent.d.ts +7 -1
- package/src/agent/ProbeAgent.js +312 -15
- package/src/agent/engines/codex.js +347 -0
- package/src/agent/engines/enhanced-claude-code.js +3 -42
- package/src/agent/mcp/built-in-server.js +334 -8
- package/src/agent/shared/Session.js +53 -0
- package/src/agent/shared/prompts.js +129 -0
|
@@ -11,6 +11,8 @@ export interface ProbeAgentOptions {
|
|
|
11
11
|
sessionId?: string;
|
|
12
12
|
/** Custom system prompt to replace the default system message */
|
|
13
13
|
customPrompt?: string;
|
|
14
|
+
/** Alias for customPrompt. More intuitive naming for system prompts. */
|
|
15
|
+
systemPrompt?: string;
|
|
14
16
|
/** Predefined prompt type (persona) */
|
|
15
17
|
promptType?: 'code-explorer' | 'engineer' | 'code-review' | 'support' | 'architect';
|
|
16
18
|
/** Allow the use of the 'implement' tool for code editing */
|
|
@@ -35,6 +37,10 @@ export interface ProbeAgentOptions {
|
|
|
35
37
|
mcpConfig?: any;
|
|
36
38
|
/** @deprecated Use mcpConfig instead */
|
|
37
39
|
mcpServers?: any[];
|
|
40
|
+
/** List of allowed tool names. Use ['*'] for all tools (default), [] or null for no tools (raw AI mode), or specific tool names like ['search', 'query', 'extract']. Supports exclusion with '!' prefix (e.g., ['*', '!bash']). */
|
|
41
|
+
allowedTools?: string[] | null;
|
|
42
|
+
/** Convenience flag to disable all tools (equivalent to allowedTools: []). Takes precedence over allowedTools if set. */
|
|
43
|
+
disableTools?: boolean;
|
|
38
44
|
/** Retry configuration for handling transient API failures */
|
|
39
45
|
retry?: RetryOptions;
|
|
40
46
|
/** Fallback configuration for multi-provider support */
|
|
@@ -227,4 +233,4 @@ export interface ProbeAgentEvents {
|
|
|
227
233
|
}
|
|
228
234
|
|
|
229
235
|
// Default export
|
|
230
|
-
export { ProbeAgent as default };
|
|
236
|
+
export { ProbeAgent as default };
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
validateAndFixMermaidResponse
|
|
56
56
|
} from './schemaUtils.js';
|
|
57
57
|
import { removeThinkingTags } from './xmlParsingUtils.js';
|
|
58
|
+
import { predefinedPrompts } from './shared/prompts.js';
|
|
58
59
|
import {
|
|
59
60
|
MCPXmlBridge,
|
|
60
61
|
parseHybridXmlToolCall,
|
|
@@ -89,6 +90,7 @@ export class ProbeAgent {
|
|
|
89
90
|
* @param {Object} options - Configuration options
|
|
90
91
|
* @param {string} [options.sessionId] - Optional session ID
|
|
91
92
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
93
|
+
* @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
|
|
92
94
|
* @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
|
|
93
95
|
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
|
|
94
96
|
* @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
|
|
@@ -125,7 +127,8 @@ export class ProbeAgent {
|
|
|
125
127
|
constructor(options = {}) {
|
|
126
128
|
// Basic configuration
|
|
127
129
|
this.sessionId = options.sessionId || randomUUID();
|
|
128
|
-
|
|
130
|
+
// Support systemPrompt alias (overrides customPrompt when both are provided)
|
|
131
|
+
this.customPrompt = options.systemPrompt || options.customPrompt || null;
|
|
129
132
|
this.promptType = options.promptType || 'code-explorer';
|
|
130
133
|
this.allowEdit = !!options.allowEdit;
|
|
131
134
|
this.enableDelegate = !!options.enableDelegate;
|
|
@@ -304,12 +307,14 @@ export class ProbeAgent {
|
|
|
304
307
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
305
308
|
*/
|
|
306
309
|
async initialize() {
|
|
307
|
-
// Check if we need to auto-detect claude-code provider
|
|
310
|
+
// Check if we need to auto-detect claude-code or codex provider
|
|
308
311
|
// This happens when no API keys are set and no provider is specified
|
|
309
|
-
if (!this.provider && !this.clientApiProvider && this.apiType !== 'claude-code') {
|
|
312
|
+
if (!this.provider && !this.clientApiProvider && this.apiType !== 'claude-code' && this.apiType !== 'codex') {
|
|
310
313
|
// Check if initializeModel marked as uninitialized (no API keys)
|
|
311
314
|
if (this.apiType === 'uninitialized') {
|
|
312
315
|
const claudeAvailable = await this.isClaudeCommandAvailable();
|
|
316
|
+
const codexAvailable = await this.isCodexCommandAvailable();
|
|
317
|
+
|
|
313
318
|
if (claudeAvailable) {
|
|
314
319
|
if (this.debug) {
|
|
315
320
|
console.log('[DEBUG] No API keys found, but claude command detected');
|
|
@@ -320,11 +325,22 @@ export class ProbeAgent {
|
|
|
320
325
|
this.provider = null;
|
|
321
326
|
this.model = this.clientApiModel || 'claude-3-5-sonnet-20241022';
|
|
322
327
|
this.apiType = 'claude-code';
|
|
328
|
+
} else if (codexAvailable) {
|
|
329
|
+
if (this.debug) {
|
|
330
|
+
console.log('[DEBUG] No API keys found, but codex command detected');
|
|
331
|
+
console.log('[DEBUG] Auto-switching to codex provider');
|
|
332
|
+
}
|
|
333
|
+
// Set provider to codex
|
|
334
|
+
this.clientApiProvider = 'codex';
|
|
335
|
+
this.provider = null;
|
|
336
|
+
this.model = this.clientApiModel || 'gpt-4o';
|
|
337
|
+
this.apiType = 'codex';
|
|
323
338
|
} else {
|
|
324
|
-
// Neither API keys nor
|
|
325
|
-
throw new Error('No API key provided and claude command
|
|
339
|
+
// Neither API keys nor CLI commands available
|
|
340
|
+
throw new Error('No API key provided and neither claude nor codex command found. Please either:\n' +
|
|
326
341
|
'1. Set an API key: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, or AWS credentials\n' +
|
|
327
|
-
'2. Install claude command from https://docs.claude.com/en/docs/claude-code'
|
|
342
|
+
'2. Install claude command from https://docs.claude.com/en/docs/claude-code\n' +
|
|
343
|
+
'3. Install codex command from https://openai.com/codex');
|
|
328
344
|
}
|
|
329
345
|
}
|
|
330
346
|
}
|
|
@@ -482,13 +498,34 @@ export class ProbeAgent {
|
|
|
482
498
|
|
|
483
499
|
/**
|
|
484
500
|
* Check if claude command is available on the system
|
|
501
|
+
* Uses execFile instead of exec to avoid shell injection risks
|
|
485
502
|
* @returns {Promise<boolean>} True if claude command is available
|
|
486
503
|
* @private
|
|
487
504
|
*/
|
|
488
505
|
async isClaudeCommandAvailable() {
|
|
489
506
|
try {
|
|
490
|
-
const {
|
|
491
|
-
|
|
507
|
+
const { execFile } = await import('child_process');
|
|
508
|
+
const { promisify } = await import('util');
|
|
509
|
+
const execFileAsync = promisify(execFile);
|
|
510
|
+
await execFileAsync('claude', ['--version'], { timeout: 5000 });
|
|
511
|
+
return true;
|
|
512
|
+
} catch (error) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Check if codex command is available on the system
|
|
519
|
+
* Uses execFile instead of exec to avoid shell injection risks
|
|
520
|
+
* @returns {Promise<boolean>} True if codex command is available
|
|
521
|
+
* @private
|
|
522
|
+
*/
|
|
523
|
+
async isCodexCommandAvailable() {
|
|
524
|
+
try {
|
|
525
|
+
const { execFile } = await import('child_process');
|
|
526
|
+
const { promisify } = await import('util');
|
|
527
|
+
const execFileAsync = promisify(execFile);
|
|
528
|
+
await execFileAsync('codex', ['--version'], { timeout: 5000 });
|
|
492
529
|
return true;
|
|
493
530
|
} catch (error) {
|
|
494
531
|
return false;
|
|
@@ -521,6 +558,25 @@ export class ProbeAgent {
|
|
|
521
558
|
return;
|
|
522
559
|
}
|
|
523
560
|
|
|
561
|
+
// Skip API key requirement for Codex CLI (uses built-in access in Codex CLI)
|
|
562
|
+
if (this.clientApiProvider === 'codex' || process.env.USE_CODEX === 'true') {
|
|
563
|
+
// Codex CLI engine will be initialized lazily in getEngine()
|
|
564
|
+
// Set minimal defaults for compatibility
|
|
565
|
+
this.provider = null;
|
|
566
|
+
// Only set model if explicitly provided, otherwise let Codex use account default
|
|
567
|
+
this.model = modelName || null;
|
|
568
|
+
this.apiType = 'codex';
|
|
569
|
+
if (this.debug) {
|
|
570
|
+
console.log('[DEBUG] Codex CLI engine selected - will use built-in access if available');
|
|
571
|
+
if (this.model) {
|
|
572
|
+
console.log(`[DEBUG] Using model: ${this.model}`);
|
|
573
|
+
} else {
|
|
574
|
+
console.log('[DEBUG] Using Codex account default model');
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
524
580
|
// Get API keys from environment variables
|
|
525
581
|
// Support both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN (used by Z.AI)
|
|
526
582
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
@@ -724,6 +780,60 @@ export class ProbeAgent {
|
|
|
724
780
|
}
|
|
725
781
|
}
|
|
726
782
|
|
|
783
|
+
// Check if we should use Codex engine
|
|
784
|
+
if (this.clientApiProvider === 'codex' || process.env.USE_CODEX === 'true') {
|
|
785
|
+
try {
|
|
786
|
+
const engine = await this.getEngine();
|
|
787
|
+
if (engine && engine.query) {
|
|
788
|
+
// Convert Vercel AI SDK format to engine format
|
|
789
|
+
// Extract the ORIGINAL user message as the main prompt (skip any warning messages)
|
|
790
|
+
// Look for user messages that are NOT the warning message
|
|
791
|
+
const userMessages = options.messages.filter(m =>
|
|
792
|
+
m.role === 'user' &&
|
|
793
|
+
!m.content.includes('WARNING: You have reached the maximum tool iterations limit')
|
|
794
|
+
);
|
|
795
|
+
const lastUserMessage = userMessages[userMessages.length - 1];
|
|
796
|
+
const prompt = lastUserMessage ? lastUserMessage.content : '';
|
|
797
|
+
|
|
798
|
+
// Pass system message and other options
|
|
799
|
+
const engineOptions = {
|
|
800
|
+
maxTokens: options.maxTokens,
|
|
801
|
+
temperature: options.temperature,
|
|
802
|
+
messages: options.messages,
|
|
803
|
+
systemPrompt: options.messages.find(m => m.role === 'system')?.content
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
// Get the engine's query result (async generator)
|
|
807
|
+
const engineStream = engine.query(prompt, engineOptions);
|
|
808
|
+
|
|
809
|
+
// Create a text stream that extracts text from engine messages
|
|
810
|
+
async function* createTextStream() {
|
|
811
|
+
for await (const message of engineStream) {
|
|
812
|
+
if (message.type === 'text' && message.content) {
|
|
813
|
+
yield message.content;
|
|
814
|
+
} else if (typeof message === 'string') {
|
|
815
|
+
// If engine returns plain strings, pass them through
|
|
816
|
+
yield message;
|
|
817
|
+
}
|
|
818
|
+
// Ignore other message types for the text stream
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Wrap the engine result to match streamText interface
|
|
823
|
+
return {
|
|
824
|
+
textStream: createTextStream(),
|
|
825
|
+
usage: Promise.resolve({}), // Engine should handle its own usage tracking
|
|
826
|
+
// Add other streamText-compatible properties as needed
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
} catch (error) {
|
|
830
|
+
if (this.debug) {
|
|
831
|
+
console.log(`[DEBUG] Failed to use Codex engine, falling back to Vercel:`, error.message);
|
|
832
|
+
}
|
|
833
|
+
// Fall through to use Vercel engine as fallback
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
727
837
|
// Initialize retry manager if not already created
|
|
728
838
|
if (!this.retryManager) {
|
|
729
839
|
this.retryManager = new RetryManager({
|
|
@@ -908,6 +1018,39 @@ export class ProbeAgent {
|
|
|
908
1018
|
this.clientApiProvider = null;
|
|
909
1019
|
}
|
|
910
1020
|
}
|
|
1021
|
+
|
|
1022
|
+
// Try Codex CLI engine if requested
|
|
1023
|
+
if (this.clientApiProvider === 'codex' || process.env.USE_CODEX === 'true') {
|
|
1024
|
+
try {
|
|
1025
|
+
const { createCodexEngine } = await import('./engines/codex.js');
|
|
1026
|
+
|
|
1027
|
+
// For Codex CLI, use a cleaner system prompt without XML formatting
|
|
1028
|
+
// since it has native MCP support for tools
|
|
1029
|
+
const systemPrompt = this.customPrompt || this.getCodexNativeSystemPrompt();
|
|
1030
|
+
|
|
1031
|
+
this.engine = await createCodexEngine({
|
|
1032
|
+
agent: this, // Pass reference to ProbeAgent for tool access
|
|
1033
|
+
systemPrompt: systemPrompt,
|
|
1034
|
+
customPrompt: this.customPrompt,
|
|
1035
|
+
sessionId: this.options?.sessionId,
|
|
1036
|
+
debug: this.debug,
|
|
1037
|
+
allowedTools: this.allowedTools, // Pass tool filtering configuration
|
|
1038
|
+
model: this.model // Pass model name (e.g., gpt-4o, o3, etc.)
|
|
1039
|
+
});
|
|
1040
|
+
if (this.debug) {
|
|
1041
|
+
console.log('[DEBUG] Using Codex CLI engine with Probe tools');
|
|
1042
|
+
if (this.customPrompt) {
|
|
1043
|
+
console.log('[DEBUG] Using custom prompt/persona');
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return this.engine;
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
console.warn('[WARNING] Failed to load Codex CLI engine:', error.message);
|
|
1049
|
+
console.warn('[WARNING] Falling back to Vercel AI SDK');
|
|
1050
|
+
this.clientApiProvider = null;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
911
1054
|
// Default to enhanced Vercel AI SDK (wraps existing logic)
|
|
912
1055
|
const { createEnhancedVercelEngine } = await import('./engines/enhanced-vercel.js');
|
|
913
1056
|
this.engine = createEnhancedVercelEngine(this);
|
|
@@ -917,6 +1060,35 @@ export class ProbeAgent {
|
|
|
917
1060
|
return this.engine;
|
|
918
1061
|
}
|
|
919
1062
|
|
|
1063
|
+
/**
|
|
1064
|
+
* Get session information including thread ID for resumability
|
|
1065
|
+
* @returns {Object} Session info with sessionId, threadId, messageCount
|
|
1066
|
+
*/
|
|
1067
|
+
getSessionInfo() {
|
|
1068
|
+
if (this.engine && this.engine.getSession) {
|
|
1069
|
+
return this.engine.getSession();
|
|
1070
|
+
}
|
|
1071
|
+
return {
|
|
1072
|
+
id: this.sessionId,
|
|
1073
|
+
threadId: null,
|
|
1074
|
+
messageCount: 0
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Close the agent and clean up resources (e.g., MCP servers)
|
|
1080
|
+
* @returns {Promise<void>}
|
|
1081
|
+
*/
|
|
1082
|
+
async close() {
|
|
1083
|
+
if (this.engine && this.engine.close) {
|
|
1084
|
+
await this.engine.close();
|
|
1085
|
+
}
|
|
1086
|
+
if (this.mcpBridge) {
|
|
1087
|
+
// Clean up MCP bridge if needed
|
|
1088
|
+
this.mcpBridge = null;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
920
1092
|
/**
|
|
921
1093
|
* Process assistant response content and detect/load image references
|
|
922
1094
|
* @param {string} content - The assistant's response content
|
|
@@ -1311,11 +1483,64 @@ export class ProbeAgent {
|
|
|
1311
1483
|
let systemPrompt = '';
|
|
1312
1484
|
|
|
1313
1485
|
// Add persona/role if configured
|
|
1314
|
-
if (this.
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1486
|
+
if (this.customPrompt) {
|
|
1487
|
+
systemPrompt += this.customPrompt + '\n\n';
|
|
1488
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
1489
|
+
systemPrompt += predefinedPrompts[this.promptType] + '\n\n';
|
|
1490
|
+
} else {
|
|
1491
|
+
// Use default code-explorer prompt
|
|
1492
|
+
systemPrompt += predefinedPrompts['code-explorer'] + '\n\n';
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Add high-level instructions about when to use tools
|
|
1496
|
+
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
1497
|
+
- search: Find code patterns using semantic search
|
|
1498
|
+
- extract: Extract specific code sections with context
|
|
1499
|
+
- query: Use AST patterns for structural code matching
|
|
1500
|
+
- listFiles: Browse directory contents
|
|
1501
|
+
- searchFiles: Find files by name patterns`;
|
|
1502
|
+
|
|
1503
|
+
if (this.enableBash) {
|
|
1504
|
+
systemPrompt += `\n- bash: Execute bash commands for system operations`;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
systemPrompt += `\n
|
|
1508
|
+
When exploring code:
|
|
1509
|
+
1. Start with search to find relevant code patterns
|
|
1510
|
+
2. Use extract to get detailed context when needed
|
|
1511
|
+
3. Prefer focused, specific searches over broad queries
|
|
1512
|
+
4. Combine multiple tools to build complete understanding`;
|
|
1513
|
+
|
|
1514
|
+
// Add workspace context
|
|
1515
|
+
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
1516
|
+
systemPrompt += `\n\nWorkspace: ${this.allowedFolders.join(', ')}`;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// Add repository structure if available
|
|
1520
|
+
if (this.fileList) {
|
|
1521
|
+
systemPrompt += `\n\n# Repository Structure\n`;
|
|
1522
|
+
systemPrompt += `You are working with a repository located at: ${this.allowedFolders[0]}\n\n`;
|
|
1523
|
+
systemPrompt += `Here's an overview of the repository structure (showing up to 100 most relevant files):\n\n`;
|
|
1524
|
+
systemPrompt += '```\n' + this.fileList + '\n```\n';
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
return systemPrompt;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
/**
|
|
1531
|
+
* Get system prompt for Codex CLI (similar to Claude but optimized for Codex)
|
|
1532
|
+
*/
|
|
1533
|
+
getCodexNativeSystemPrompt() {
|
|
1534
|
+
let systemPrompt = '';
|
|
1535
|
+
|
|
1536
|
+
// Add persona/role if configured
|
|
1537
|
+
if (this.customPrompt) {
|
|
1538
|
+
systemPrompt += this.customPrompt + '\n\n';
|
|
1539
|
+
} else if (this.promptType && predefinedPrompts[this.promptType]) {
|
|
1540
|
+
systemPrompt += predefinedPrompts[this.promptType] + '\n\n';
|
|
1541
|
+
} else {
|
|
1542
|
+
// Use default code-explorer prompt
|
|
1543
|
+
systemPrompt += predefinedPrompts['code-explorer'] + '\n\n';
|
|
1319
1544
|
}
|
|
1320
1545
|
|
|
1321
1546
|
// Add high-level instructions about when to use tools
|
|
@@ -1747,8 +1972,9 @@ When troubleshooting:
|
|
|
1747
1972
|
const baseMaxIterations = this.maxIterations || MAX_TOOL_ITERATIONS;
|
|
1748
1973
|
const maxIterations = options.schema ? baseMaxIterations + 4 : baseMaxIterations;
|
|
1749
1974
|
|
|
1750
|
-
// Check if we're using
|
|
1975
|
+
// Check if we're using CLI-based engines which handle their own agentic loop
|
|
1751
1976
|
const isClaudeCode = this.clientApiProvider === 'claude-code' || process.env.USE_CLAUDE_CODE === 'true';
|
|
1977
|
+
const isCodex = this.clientApiProvider === 'codex' || process.env.USE_CODEX === 'true';
|
|
1752
1978
|
|
|
1753
1979
|
if (isClaudeCode) {
|
|
1754
1980
|
// For Claude Code, bypass the tool loop entirely - it handles its own internal dialogue
|
|
@@ -1820,6 +2046,77 @@ When troubleshooting:
|
|
|
1820
2046
|
}
|
|
1821
2047
|
}
|
|
1822
2048
|
|
|
2049
|
+
// Handle Codex engine (same pattern as Claude Code)
|
|
2050
|
+
if (isCodex) {
|
|
2051
|
+
// For Codex, bypass the tool loop entirely - it handles its own internal dialogue
|
|
2052
|
+
if (this.debug) {
|
|
2053
|
+
console.log(`[DEBUG] Using Codex engine - bypassing tool loop (black box mode)`);
|
|
2054
|
+
console.log(`[DEBUG] Sending question directly to Codex: ${message.substring(0, 100)}...`);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
// Send the message directly to Codex and collect the response
|
|
2058
|
+
try {
|
|
2059
|
+
const engine = await this.getEngine();
|
|
2060
|
+
if (engine && engine.query) {
|
|
2061
|
+
let assistantResponseContent = '';
|
|
2062
|
+
let toolBatch = null;
|
|
2063
|
+
|
|
2064
|
+
// Query Codex directly with the message and schema
|
|
2065
|
+
for await (const chunk of engine.query(message, options)) {
|
|
2066
|
+
if (chunk.type === 'text' && chunk.content) {
|
|
2067
|
+
assistantResponseContent += chunk.content;
|
|
2068
|
+
if (options.onStream) {
|
|
2069
|
+
options.onStream(chunk.content);
|
|
2070
|
+
}
|
|
2071
|
+
} else if (chunk.type === 'toolBatch' && chunk.tools) {
|
|
2072
|
+
// Store tool batch for processing after response
|
|
2073
|
+
toolBatch = chunk.tools;
|
|
2074
|
+
if (this.debug) {
|
|
2075
|
+
console.log(`[DEBUG] Received batch of ${chunk.tools.length} tool events from Codex`);
|
|
2076
|
+
}
|
|
2077
|
+
} else if (chunk.type === 'error') {
|
|
2078
|
+
throw chunk.error;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// Emit tool events after response is complete (batch mode)
|
|
2083
|
+
if (toolBatch && toolBatch.length > 0 && this.events) {
|
|
2084
|
+
if (this.debug) {
|
|
2085
|
+
console.log(`[DEBUG] Emitting ${toolBatch.length} tool events from Codex batch`);
|
|
2086
|
+
}
|
|
2087
|
+
for (const toolEvent of toolBatch) {
|
|
2088
|
+
this.events.emit('toolCall', toolEvent);
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
// Update history with the exchange
|
|
2093
|
+
this.history.push(userMessage);
|
|
2094
|
+
this.history.push({
|
|
2095
|
+
role: 'assistant',
|
|
2096
|
+
content: assistantResponseContent
|
|
2097
|
+
});
|
|
2098
|
+
|
|
2099
|
+
// Store conversation history
|
|
2100
|
+
// TODO: storeConversationHistory is not yet implemented for Codex
|
|
2101
|
+
// await this.storeConversationHistory(this.history, oldHistoryLength);
|
|
2102
|
+
|
|
2103
|
+
// Emit completion hook
|
|
2104
|
+
await this.hooks.emit(HOOK_TYPES.COMPLETION, {
|
|
2105
|
+
sessionId: this.sessionId,
|
|
2106
|
+
prompt: message,
|
|
2107
|
+
response: assistantResponseContent
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
return assistantResponseContent;
|
|
2111
|
+
}
|
|
2112
|
+
} catch (error) {
|
|
2113
|
+
if (this.debug) {
|
|
2114
|
+
console.error('[DEBUG] Codex error:', error);
|
|
2115
|
+
}
|
|
2116
|
+
throw error;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
|
|
1823
2120
|
if (this.debug) {
|
|
1824
2121
|
console.log(`[DEBUG] Starting agentic flow for question: ${message.substring(0, 100)}...`);
|
|
1825
2122
|
if (options.schema) {
|
|
@@ -1827,7 +2124,7 @@ When troubleshooting:
|
|
|
1827
2124
|
}
|
|
1828
2125
|
}
|
|
1829
2126
|
|
|
1830
|
-
// Tool iteration loop (only for non-
|
|
2127
|
+
// Tool iteration loop (only for non-CLI engines like Vercel/Anthropic/OpenAI)
|
|
1831
2128
|
while (currentIteration < maxIterations && !completionAttempted) {
|
|
1832
2129
|
currentIteration++;
|
|
1833
2130
|
if (this.cancelled) throw new Error('Request was cancelled by the user');
|